Это четвертый шаг нашего примера для реализации пакетного редактирования с помощью элемента управления Ignite UI for Angular Grid и веб-API. Вы можете найти предыдущий шаг, на котором мы создали приложение Angular с помощью интерфейса командной строки Ignite UI, здесь.

Шаг 4. Обновите проект интерфейса командной строки Ignite UI, чтобы он работал с веб-API

В этом разделе мы используем:

  • Код Visual Studio

Чтобы изучить IgxGrid project и определить, какие изменения требуются для нашего сценария, перейдите в корневую папку проекта, где находится файл packages.json. Щелкните папку правой кнопкой мыши и выберите в меню Открыть с помощью кода. Если на вашем компьютере не установлен Visual Studio Code - вы можете получить его здесь.

Теперь, когда у нас есть вся файловая структура проекта, открытая в Code, разверните srcappgrid-batch-edit.

Откройте data.ts файл. Вы видите, что он содержит фиктивные данные, которые использует шаблон. Нам это не нужно, так как мы будем кормить сетку собственными данными, поэтому вы можете удалить этот файл.

Теперь откройте файл grid-batch-editing.component.ts и удалите из импорта в верхней части кода:

Нам нужно создать инъекционный сервис, который будет получать данные из серверной части, а также отправлять транзакции, которые мы делаем, на сервер. Мы также должны создать интерфейс службы, который необходим службе для получения данных с сервера.

Вы можете прочитать больше об Angular Services и Dependency Injection здесь.

Чтобы создать интерфейс, щелкните правой кнопкой мыши папку grid-batch-editing и выберите «Новый файл».

Назовите его city.ts. Вставьте внутрь следующий код:

Это наш интерфейс, который моделирует наш источник данных.

Теперь давайте создадим сервис, который будет использовать этот интерфейс. Мы можем сгенерировать сервис с помощью команды ng g следующим образом:

ng g service city

На этом этапе мы должны соблюдать подход к отправке запросов, который мы использовали на шаге 2 этого руководства. Ниже мы демонстрируем, как будет выглядеть наш сервис в случае, если мы решили использовать единый запрос к серверу, на котором будут обрабатываться наши транзакции.

Если вы решили использовать второй подход - когда вы обрабатываете транзакции на стороне клиента, а затем отправляете их на сервер отдельными запросами, вам следует реализовать другой метод commitCities() в этой службе. Мы объясним различия ниже. А теперь давайте начнем с нашего примера.

Вставьте следующий код во вновь созданную службу:

Здесь мы устанавливаем конечную точку, на которую будем ориентироваться при получении данных с сервера и при отправке на него обновлений. Обратите внимание, что мы установили порт, на котором будет работать веб-API, на 36830. Когда мы вернемся к проекту веб-API, мы обновим настройки проекта, чтобы быть уверенными, что он всегда использует этот порт.

Наш сервис реализует всего два метода. getCities(), который выполняет запрос GET и возвращает данные из нашей базы данных, и commitCities(), который отправляет запрос POST на сервер, чтобы отправить внесенные нами изменения.

Если вы реализуете сценарий, в котором транзакции обрабатываются внутри службы, а не на сервере, замените метод commitCities() следующим:

Что происходит выше, мы проверяем, есть ли у нас транзакция для каждого типа запроса, и если да, то помещаем соответствующий запрос в requests array. Это гарантирует, что мы не будем отправлять на сервер пустые запросы.

Мы merge все возможные запросы в один Observable, чтобы мы могли подписаться на него в нашем компоненте и выполнять логику после обработки всех транзакций.

Теперь, когда наша служба готова, давайте вернемся к файлу grid-batch-editing.component.ts, где мы будем его использовать.

Сначала импортируйте интерфейс города:

Найдите addProductId property и удалите его.

Затем измените эту строку кода выше:

со следующим:

Затем перейдите к конструктору и замените его следующей строкой:

Затем перейдите к методу ngOnInit () и обновите его следующим образом:

Посмотрим, что здесь происходит. На ngOnInit() мы хотим выполнить несколько задач инициализации. Мы подписываемся на cities() метод CityService, который мы внедрили в конструктор. Когда мы получаем ответ, мы присваиваем полученные данные (фактические данные из нашей базы данных) data property класса. На этом этапе наша сетка будет заполнена данными.

Мы продолжаем со следующей функциональностью, предоставляемой нашим приложением, - добавлением новой записи в базу данных. Перейдите к методу addRow(). Он предоставляет шаблон для новой записи. Мы бы установили для свойств города некоторые значимые значения по умолчанию, и после того, как пользователь добавит новый город в сетку, мы ожидаем, что он обновит поля. При добавлении в сетку важно создать случайный временный идентификатор для новой записи, поскольку транзакции ожидают, что все города будут иметь свойство CityID. Если, например, мы не предоставим значение для этого свойства, мы не сможем добавить более одной новой записи, поскольку undefined будет установлен в качестве значения для идентификатора, а при добавлении второй новой строки - он найдет такую уникальный идентификатор уже существует.

Нам также нужно создать метод generateID(). Мы бы добавили его в конец кода:

Имейте в виду, что это очень упрощенный пример создания ценности. В реальных приложениях вы хотели бы реализовать более продвинутый метод, поскольку вы не хотите дублировать случайно сгенерированные значения.

В этом файле осталось обновить метод commit(). Здесь мы будем отправлять обновления на сервер. Метод должен выглядеть так:

Теперь наша сетка выглядит хорошо. Однако, поскольку мы внесли много изменений в сетку, мы не должны забывать обновить разметку HTML, поскольку мы переименовали множество свойств.

Откройте grid-batch-editing.component.html и найдите элемент <igx-grid> с идентификатором #gridRowEditTransaction. Замените его следующим:

Если вы присмотритесь, вы увидите, что в этом коде используется канал transformDates. Подробнее о каналах в Angular вы можете узнать в этой статье. Мы будем использовать наш канал для преобразования дат праздников, поступающих с сервера, в виде строк в объекты Date, которые IgxGrid могут использовать.

Итак, давайте создадим новую трубу. В командной строке выполните следующую команду:

ng g pipe transformDates

Эта команда создаст новую папку с именем pipes внутри папки app вашего проекта. Откройте эту новую папку, и вы обнаружите, что внутри создаются два файла. Первый, transform-dates.pipe.spec.ts, это файл, в который будут добавлены автоматизированные тесты, проверяющие канал. Существует даже предопределенный сценарий тестирования, который проверяет, успешно ли инициализирован канал. Однако тестирование нашего приложения выходит за рамки цели нашего руководства, поэтому вместо этого мы более внимательно рассмотрим второй файл.

transform-dates.pipe.ts - вот где на самом деле реализован наш пайп. Замените его содержимое следующим кодом:

Этот канал преобразует записи, которые мы получаем от сервера, изменяя значение HolidayDatе, имеющее тип string, на объект Date. После обновления свойства HolidayDate каждой записи конвейер возвращает преобразованные записи, и они загружаются в сетку.

Прежде чем мы будем готовы его протестировать, мы должны обновить файл app.module.ts. Откройте его и добавьте этот импорт (если вы создали службу с помощью команды ng g, служба будет автоматически импортирована в app.module.ts):

Затем добавьте HttpClientModule в массив imports[]. И, наконец, добавьте CityService в массив providers:

На этом мы закончили со стороной клиента. Теперь давайте вернемся к проекту веб-API и внесем некоторые небольшие изменения, чтобы он плавно работал с проектом Angular.

Откройте проект веб-API в Visual Studio и щелкните правой кнопкой мыши проект CityService. Щелкните "Свойства", и откроется окно свойств проекта. Выберите Интернет в меню слева и перейдите к полю URL-адрес проекта. Установите для него значение http: // localhost: 36830 / и сохраните проект (Ctrl + S). Вам может быть предложено создать виртуальный каталог - примите его.

Скомпилируйте проект и повторно запустите его с _50 _ + _ 51_. Затем обновите приложение Angular, и мы увидим, что сетка загружена данными!

Ой! Выглядит не очень хорошо… Откройте инструменты разработки (F12) и перейдите на вкладку «Консоль», чтобы увидеть, доступно ли сообщение об ошибке.

Access to XMLHttpRequest at ‘http://localhost:36830/api/cities/' from origin ‘http://localhost:4200' has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

Политика CORS блокирует наш запрос к серверу. Однако что такое CORS из первых рук?

Совместное использование ресурсов между источниками (CORS) - это механизм, который использует дополнительные заголовки HTTP, чтобы сообщить браузеру, что веб-приложение, работающее в одном источнике (домене), имеет разрешение на доступ к выбранным ресурсам с сервера в другом источнике. Веб-приложение выполняет HTTP-запрос с несколькими источниками, когда запрашивает ресурс, источник которого отличается от источника (домен, протокол и порт).

Теперь это имеет смысл. Наш проект Angular работает на другом порту, чем наш веб-API. Хорошо, что ASP.NET Web API 2 поддерживает CORS! Чтобы включить поддержку CORS, мы должны добавить в проект NuGet-пакет Microsoft.AspNet.WebApi.Cors.

Щелкните правой кнопкой мыши проект CityService и выберите «Управление пакетами NuGet…». Когда открывается представление диспетчера пакетов NuGet, выберите вкладку «Обзор» и найдите Microsoft.AspNet.WebApi.Cors. Выберите нужный пакет и нажмите «Установить».

Когда в диалоговом окне «Предварительный просмотр изменений» вас попросят внести изменения в решение, нажмите «ОК».

В следующем диалоговом окне «Принятие лицензии» нажмите «Я принимаю».

После их принятия будет установлен пакет NuGet.

Как только это будет сделано, разверните папку App_Start в своем решении и откройте файл WebApiConfig.cs.

Добавьте этот оператор using:

И добавьте в метод Register() следующий код:

Имейте в виду, что это способ обработки CORS, если ваш контроллер ApiController, как в нашем случае. Мы также должны добавить атрибут [EnableCors] к самому контроллеру. Добавьте в свой контроллер следующие атрибуты:

Под контроллером добавьте следующий класс:

Если бы ваш контроллер не был ApiController, это не сработало бы для вас. Вам нужно будет настроить CORS в Web.config проекта.

Распространенная проблема, с которой вы можете столкнуться, когда у вас есть несколько контроллеров в вашем проекте, - это настроить политики CORS в обоих местах - Web.config и WebApiConfig.cs. Если это произойдет, вы увидите такую ​​ошибку:

Access to XMLHttpRequest at ‘’’ from origin ‘’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘*, *’, but only one is allowed.

Если вы столкнулись с таким случаем - обязательно закомментируйте раздел в своем Web.config и настройте свой ApiController для обработки запроса.

На этом этапе мы готовы протестировать наше приложение. Скрещенные пальцы! Мы переходим к заключительному разделу нашего урока!

Мы подошли к концу нашего руководства по реализации функции пакетного редактирования сетки Ignite UI for Angular! Спасибо, что поддержали меня в этой довольно длинной публикации! Увидимся на последнем этапе этой серии. Следите за обновлениями!