如何在angular.js 1中使用$ compile正确绑定'bindings'中的对象?

时间:2016-12-23 02:44:58

标签: javascript angularjs angularjs-directive angularjs-scope angularjs-components

我想动态编译组件以将其插入特定的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.mergeitem控制器实例初始化之前传递ListItemController是一个主要原因。

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

1 个答案:

答案 0 :(得分: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      
        }
    }
}