简体   繁体   English

ServiceNow:ngTable无法从服务器获取要加载的数据

[英]ServiceNow: ngTable cannot get data to load from sever

Our team is building a table widget in ServiceNow and decided to give ngTable a try. 我们的团队正在ServiceNow中构建表小部件,并决定尝试ngTable。 We've loaded the dependency and tested that it renders correctly with the example on the github site. 我们已经加载了依赖项,并通过github站点上的示例测试了它能否正确呈现。 We now want to load our data from an object array in the server script called data.onbCase. 现在,我们要从服务器脚本中名为data.onbCase的对象数组中加载数据。 However, when we try to load the data this way, we get an error message in the console saying: 但是,当我们尝试以这种方式加载数据时,会在控制台中收到一条错误消息,内容为:

TypeError: Cannot read property 'length' of undefined TypeError:无法读取未定义的属性“ length”

In our client script we have total: c.onbCase.length, and are unsure why this is creating an error. 在我们的客户端脚本中,共有:c.onbCase.length,并且不确定为什么会产生错误。 Are we missing something here? 我们在这里缺少什么吗?

  <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();
        });
    }

This is a classic example of not understanding the order or operations of JS promises. 这是一个不了解JS promise的顺序或操作的经典示例。 Your ngTable initialization is getting called BEFORE THE DATA HAS RETURNED. 在返回数据之前,将调用ngTable初始化。

The problem is that your call to ngTableParams() comes directly after making your server.get call. 问题是您对ngTableParams()调用是在进行server.get调用之后直接进行的。 You don't want to run this until control moves to within the .then() response. 您不希望在控件移至.then()响应内之前运行它。 You do this by wrapping the new ngTableParams() call in a function and calling it when the server call has completed. 为此,您可以将new ngTableParams()调用包装在一个函数中,并在服务器调用完成后对其进行调用。 This is the correct way to structure your code: 这是构造代码的正确方法:

  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) {
          ...
        }
      });

   }

If you set breakpoints in your browser's debugger in your original code, you will see that $scope.usersTable = new ngTableParams({...}) is called well before the server call ever returns and c.onbCase is undefined. 如果您使用原始代码在浏览器的调试器中设置断点,则会看到$scope.usersTable = new ngTableParams({...})在服务器调用返回之前c.onbCase被调用,并且c.onbCase未定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM