AngularJS ng-repeat未使用ng-include检测到动态生成的数组

时间:2022-12-02 17:32:54

Problem

I'm finding ng-repeat directive isn't able to track the addition of a new array.
In my example the new array is 'options'.
The directive is part of a template being displayed using ng-dialog (3rd party lib).
If i close the dialogbox and open it again the ng-repeat will pick up those changes I made before closing it.

我发现ng-repeat指令无法跟踪新数组的添加。在我的例子中,新数组是'选项'。该指令是使用ng-dialog(第三方库)显示的模板的一部分。如果我关闭对话框并再次打开它,ng-repeat将在关闭它之前获取我所做的更改。

I've tried $scope.$apply(); But I get a warning that it is already running.

我试过$ scope。$ apply();但我得到一个警告,它已经在运行了。

Update ++

The solution I ended up using was adding a function on the ng-init to check the existence of that array first, if it didn't exist it created it and then assigned it to the new variable.

我最终使用的解决方案是在ng-init上添加一个函数来检查该数组是否存在,如果它不存在则创建它然后将其分配给新变量。

Here is a more in depth example,
Writing this jsFiddle has pointed out the issue is within the ng-include/ng-repeat - without this it is fine. http://jsfiddle.net/20mobk2h/56/
http://jsfiddle.net/20mobk2h/61/

这是一个更深入的例子,写这个jsFiddle已经指出问题是在ng-include / ng-repeat中 - 没有这个就没关系。 http://jsfiddle.net/20mobk2h/56/ http://jsfiddle.net/20mobk2h/61/

The ng-repeat loops on an array called options that may or may not exist.

数组上的ng-repeat循环称为可能存在或不存在的选项。

<div ng-init="options = element.options">
    <div ng-repeat="option in options" ng-include="'optionsTree'"></div>
</div>

I add a new option by:

我添加了一个新选项:

$scope.addItem = function(item) {

    if(!item.options){
        item.options = [];
    }

    var obj = {
        val: 'blah'
    };

    item.options.push(obj);
}

3 个解决方案

#1


1  

Change this code:

更改此代码:

<div ng-init="options = item.options">
    <div ng-repeat="option in options" ng-include="'nest_options'"></div>
</div>

to this:

对此:

<div>
    <div ng-repeat="option in item.options" ng-include="'nest_options'"></div>
</div>

The problem here is that when you assign item.options to new variable options you break reference with item object, because for the first time (when item.options is undefined) options is undefined and primitive values are passed by value in Javascript. So later when you change options property (by adding new array element) this change is not reflected in options variable.

这里的问题是,当你将item.options分配给新的变量选项时,你会破坏与item对象的引用,因为第一次(当item.options未定义时)选项是未定义的,原始值是通过Javascript中的值传递的。因此,稍后当您更改选项属性(通过添加新数组元素)时,此更改不会反映在选项变量中。

However when you open popup for the second time, item.options is no longer undefined, it's already an object (array), so assignment options = item.options results into normal object reference, and changes to item.options are mirrored in item.

但是,当您第二次打开弹出窗口时,item.options不再是未定义的,它已经是一个对象(数组),因此赋值选项= item.options会导致正常的对象引用,而item.options的更改会在item中进行镜像。

Demo: http://jsfiddle.net/20mobk2h/57/

#2


1  

$scope.$apply() should really be the solution to your problem.

$ scope。$ apply()应该是你问题的解决方案。

Try using this wrapper to $scope.$apply()

尝试将此包装器用于$ scope。$ apply()

$scope.safeApply = function(fn) {
  var phase = this.$root.$$phase;
  if(phase == '$apply' || phase == '$digest') {
    if(fn && (typeof(fn) === 'function')) {
      fn();
    }
  } else {
    this.$apply(fn);
  }
};

And then just replace $apply with safeApply wherever you need it

然后在任何需要的地方用safeApply替换$ apply

$scope.safeApply(function() {
  alert('Now I'm wrapped for protection!');
});

Probably passing it the function you need running. Using this you should be able to respect the apply - digest cycle and run the apply only when it is allowed.

可能会传递你需要运行的功能。使用此方法,您应该能够尊重apply - digest循环并仅在允许时运行apply。

Taken from here

从这里开始

#3


0  

could you write full code of your controller and the page ? Have you specified ng-controller in yr page and routeProvider both ? Remove ng-controller from page if its specified in routeProvider.

你能写出你的控制器和页面的完整代码吗?你有没有在页面和routeProvider中指定ng-controller?如果在routeProvider中指定ng-controller,则从页面中删除ng-controller。

#1


1  

Change this code:

更改此代码:

<div ng-init="options = item.options">
    <div ng-repeat="option in options" ng-include="'nest_options'"></div>
</div>

to this:

对此:

<div>
    <div ng-repeat="option in item.options" ng-include="'nest_options'"></div>
</div>

The problem here is that when you assign item.options to new variable options you break reference with item object, because for the first time (when item.options is undefined) options is undefined and primitive values are passed by value in Javascript. So later when you change options property (by adding new array element) this change is not reflected in options variable.

这里的问题是,当你将item.options分配给新的变量选项时,你会破坏与item对象的引用,因为第一次(当item.options未定义时)选项是未定义的,原始值是通过Javascript中的值传递的。因此,稍后当您更改选项属性(通过添加新数组元素)时,此更改不会反映在选项变量中。

However when you open popup for the second time, item.options is no longer undefined, it's already an object (array), so assignment options = item.options results into normal object reference, and changes to item.options are mirrored in item.

但是,当您第二次打开弹出窗口时,item.options不再是未定义的,它已经是一个对象(数组),因此赋值选项= item.options会导致正常的对象引用,而item.options的更改会在item中进行镜像。

Demo: http://jsfiddle.net/20mobk2h/57/

#2


1  

$scope.$apply() should really be the solution to your problem.

$ scope。$ apply()应该是你问题的解决方案。

Try using this wrapper to $scope.$apply()

尝试将此包装器用于$ scope。$ apply()

$scope.safeApply = function(fn) {
  var phase = this.$root.$$phase;
  if(phase == '$apply' || phase == '$digest') {
    if(fn && (typeof(fn) === 'function')) {
      fn();
    }
  } else {
    this.$apply(fn);
  }
};

And then just replace $apply with safeApply wherever you need it

然后在任何需要的地方用safeApply替换$ apply

$scope.safeApply(function() {
  alert('Now I'm wrapped for protection!');
});

Probably passing it the function you need running. Using this you should be able to respect the apply - digest cycle and run the apply only when it is allowed.

可能会传递你需要运行的功能。使用此方法,您应该能够尊重apply - digest循环并仅在允许时运行apply。

Taken from here

从这里开始

#3


0  

could you write full code of your controller and the page ? Have you specified ng-controller in yr page and routeProvider both ? Remove ng-controller from page if its specified in routeProvider.

你能写出你的控制器和页面的完整代码吗?你有没有在页面和routeProvider中指定ng-controller?如果在routeProvider中指定ng-controller,则从页面中删除ng-controller。