0

我想要动态地编译组件以将其插入到特定的DOM元素(DOM也是由第三方库动态创建的)。 所以,我用$compile,$scope

https://jsbin.com/gutekat/edit?html,js,console,output

// ListController $postLink life cycle hook 

function $postLink() { 
    ... 

    $timeout(function() { 
    ctrl.items.splice(0, 1); 
    $log.debug('First item of array is removed'); 
    $log.debug(ctrl.items); 
    }, 2000); 
} 

但低于$onChanges生命周期钩在ListItemController不执行。

// ListItemController $onChanges life cycle hook 

function $onChanges(changes) { 
    if (!changes.item.isFirstChange()) { 
    $log.debug(changes); // Not executed 
    } 
} 

我想这angular.merge通过控制器实例初始化item之前ListItemController是一个重要原因。

var itemScope = $scope.$new(true, $scope); 
itemScope = angular.merge(itemScope, { 
    $ctrl: { 
    item: item 
    } 
}); 
+0

$ onChanges只听你把绑定的属性,因为'item'不绑定,它的任何变化都不会触发$ onChanges功能,你应该使用$来代替手表。 –

+0

@AnonyC然后,如何在'ListController'中编译时在'listItem'组件绑定中正确传递'item'对象? – taehwanno

回答

1

我修改了一下代码,说明了单向绑定是怎么回事。

angular.module('app', [ 
    'list.component', 
    'list-item.component' 
]); 

/** 
* list.component 
*/ 
angular 
    .module('list.component', []) 
    .component('list', { 
     controller: ListController, 
     template: '<div id="list"></div>' 
    }); 

ListController.$inject = ['$compile', '$document', '$log', '$scope', '$timeout']; 
function ListController($compile, $document, $log, $scope, $timeout) { 
    var ctrl = this; 

    ctrl.$onInit = $onInit; 
    ctrl.$postLink = $postLink; 

    function $onInit() { 
     ctrl.items = [ 
      { 
       id: 0, 
       value: 'a' 
      }, 
      { 
       id: 1, 
       value: 'b' 
      }, 
      { 
       id: 2, 
       value: 'c' 
      } 
     ]; 
    } 

    function $postLink() { 
     var index = 0; 
     // Not entirely sure what you need to do this. This can easily be done in the template. 
     /** ie: 
     * template: '<div id="list" ng-repeat="item in $ctrl.items"><list-item item="item"></list-item></div>' 
     **/ 

     var iElements = ctrl.items.map(function (item) { 
      var template = '<list-item item="$ctrl.items[' + (index) + ']"></list-item>'; 
      index++; 
      // you don't want to create an isolate scope here for the 1 way binding of the item. 
      return $compile(template)($scope.$new(false)); 
     }); 

     var listDOM = $document[0].getElementById('list'); 
     var jqListDOM = angular.element(listDOM); 

     iElements.forEach(function (iElement) { 
      jqListDOM.append(iElement); 
     }); 

     $timeout(function() { 
      // this will trigger $onChanges since this is a reference change 
      ctrl.items[0] = { id: 3, value: 'ss' }; 
      // this however, will not trigger the $onChanges, if you need to use deep comparison, consider to use $watch 
      ctrl.items[1].value = 's'; 
      ctrl.items[2].value = 's'; 
     }, 2000); 
    } 
} 

/** 
* list-item.component 
*/ 
angular 
    .module('list-item.component', []) 
    .component('listItem', { 
     bindings: { 
      item: '<' 
     }, 
     controller: ListItemController, 
     template: '<div class="listItem">{{ $ctrl.item.value }}</div>' 
    }); 

ListItemController.$inject = ['$log']; 
function ListItemController($log) { 
    var ctrl = this; 

    ctrl.$onChanges = $onChanges; 

    function $onChanges(changes) { 
     if (!changes.item.isFirstChange()) { 
      $log.debug(changes); // Not executed  
     } 
    } 
}