ServiceNow: ngTable не может получить данные для загрузки с сервера - PullRequest
0 голосов
/ 26 февраля 2019

Наша команда создает виджет таблицы в ServiceNow и решила попробовать ngTable.Мы загрузили зависимость и проверили, что она правильно отображается на примере сайта github.Теперь мы хотим загрузить наши данные из массива объектов в серверном скрипте с именем data.onbCase.Однако, когда мы пытаемся загрузить данные таким образом, в консоли появляется сообщение об ошибке:

TypeError: Невозможно прочитать свойство 'length' с неопределенным значением

В нашем клиентском скрипте мы имеемtotal: c.onbCase.length и не уверены, почему это приводит к ошибке.Мы что-то здесь упускаем?

  <div class="panel panel-default" style="margin-bottom:200px;">
      <div class="panel-heading">
        <span class="panel-title"><i class="fa fa-{{c.glyph}}" aria-hidden="true"></i>&nbsp; {{c.title}}</span>
      </div>

      <div class="panel-body" ng-if="c.data.loading">
        <span><i class="fa fa-spinner fa-spin fa-3x fafw"></i>
          <span class="sr-only">Loading...</span>
        </span>
      </div>

      <div class="panel-body table-responsive" ng-if="!c.data.loading">
        <h4 ng-if="c.options.filter">Table Filter: {{c.options.filter}}</h4>
        <table id="print_table" class="display table table-striped table-hover" ng-table ="usersTable" show-filter=true>
          <tr ng-click="c.onWidget('batch_qa_form_list',item.sys_id, item.short_description);" 
              ng-repeat="item in c.onbCase track by $index" 
              ng-if="item.case_visible">
            <td ng-show="c.options.case_number" data-title="{{item.number}}" sortable="'number'" filter="{ 'number': 'text' }">{{item.number}}</td>
            <td ng-show="c.options.last_name" data-title="{{item.last_name}}" sortable="'last_name'" filter="{ 'last_name': 'text' }">{{item.last_name}}</td>
            <td ng-show="c.options.first_name" data-title="{{item.first_name}}" sortable="'first_name'" filter="{ 'first_name': 'text' }">{{item.first_name}}</td>
            <td ng-show="c.options.case_short_description" data-title="{{item.short_description}}" sortable="'short_description'" filter="{ 'short_description': 'text' }">{{item.short_description}}</td>
            <td ng-show="c.options.start_date" data-title="{{item.start_date}}" sortable="'start_date'" filter="{ 'start_date': 'text' }">{{item.start_date | date:'shortDate':'Z'}}</td>
            <td ng-show="c.options.work_location" data-title="{{item.location}}" sortable="'location'" filter="{ 'location': 'text' }">{{item.location}}</td>
            <td ng-show="c.options.form_review_status" data-title="{{item.form_review_status}}" sortable="'all_approved'" filter="{ 'all_approved': 'text' }">        
              <i ng-if="item.all_approved=='All Forms Reviewed'" class="fa fa-check-circle fa-lg success"></i>
              <i ng-if="item.all_approved=='Pending Review'" class="fa fa-exclamation-circle fa-lg warning" uib-tooltip="{{item.number_pending}} items pending review" tooltip-placement="left" title=""></i>
            </td>
          </tr>
        </table>
      </div>
    </div>

    function($scope, spUtil, spModal, $filter, ngTableParams) {

        var c = this;

        //Set value to show loading spinner
        c.data.loading = true;

        function initialize() {
            c.server.get({
                action: 'retrieve_data'
            }).then(function(response) {
                //Set value to hide loading spinner
                c.data.loading = false;

                //Get link data
                c.onbCase = response.data.onbCase;
            });
        }
    initialize();

        $scope.usersTable = new ngTableParams({
            page: 1,
            count: 5
        }, {
            total: c.onbCase.length,
            getData: function ($defer, params) {
                $scope.data = params.sorting() ? $filter('orderBy')(c.onbCase, params.orderBy()) : c.onbCase;
                $scope.data = params.filter() ? $filter('filter')($scope.data, params.filter()) : $scope.data;
                $scope.data = $scope.data.slice((params.page() - 1) * params.count(), params.page() * params.count());
                $defer.resolve($scope.data);
            }
        });

        spUtil.recordWatch($scope, "x_dnf_federal_hr_o_federal_form_review", "", function(name, data) {
            initialize();
        });
    }

1 Ответ

0 голосов
/ 26 февраля 2019

Это классический пример непонимания порядка или операций обещаний JS.Ваша инициализация ngTable вызывается до того, как данные возвращены.

Проблема в том, что ваш вызов на ngTableParams() приходит сразу после вашего server.get вызова.Вы не хотите запускать это, пока управление не переместится в пределах ответа .then().Вы делаете это, оборачивая вызов new ngTableParams() в функцию и вызывая его, когда серверный вызов завершен.Это правильный способ структурировать ваш код:

  function initialize() {
    c.server.get({
      action: 'retrieve_data'
    }).then(function(response) {
      //Set value to hide loading spinner
      c.data.loading = false;

      //Get link data
      c.onbCase = response.data.onbCase;

      // don't run the ngTable init until the http call has returned
      ngTableInit();
    });
  }
  initialize();

  //wrap your ngTableParams constructor in a function
  function ngTableInit() {
      $scope.usersTable = new ngTableParams({
        page: 1,
        count: 5
      }, {
        total: c.onbCase.length,
        getData: function ($defer, params) {
          ...
        }
      });

   }

Если вы установили точки останова в отладчике вашего браузера в исходном коде, вы увидите, что $scope.usersTable = new ngTableParams({...}) вызывается задолго до того, как вызов сервера когда-либо вернется, и c.onbCase не определено.

...