Директивы в AngularJS не обновляет на область изменения переменных



Я попытался написать небольшую директиву, чтобы обернуть ее содержимое с другим файлом шаблона.



этот код:



<layout name="Default">My cool content</layout>


должен иметь этот вывод:



<div class="layoutDefault">My cool content</div>


потому, что макет "по умолчанию" этот код:



<div class="layoutDefault">{{content}}</div>


вот код директивы:



app.directive('layout', function($http, $compile){
return {
restrict: 'E',
link: function(scope, element, attributes) {
var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
$http.get(scope.constants.pathLayouts + layoutName + '.html')
.success(function(layout){
var regexp = /^([sS]*?){{content}}([sS]*)$/g;
var result = regexp.exec(layout);

var templateWithLayout = result[1] + element.html() + result[2];
element.html($compile(templateWithLayout)(scope));
});
}
}


});



моя проблема:



когда я использую переменные в шаблон (в шаблоне макета или внутри тега макета), например. {{whatever}} Он просто работает изначально. Если я обновлю whatever переменная, директива больше не обновляется. Все функции связи будет только один раз срабатывает.



Я думаю, что AngularJS не знает, что эта директива использует переменные области видимости и поэтому она не будет обновляться. Но я понятия не имею, как исправить это поведение.

647   9  

9 ответов:

вы должны создать связанную переменную области и наблюдать за ее изменениями:

return {
   restrict: 'E',
   scope: {
     name: '='
   },
   link: function(scope) {
     scope.$watch('name', function() {
        // all the code here...
     });
   }
};

мне также нужно было решение этой проблемы, и я использовал ответы в этой теме, чтобы придумать следующее:

.directive('tpReport', ['$parse', '$http', '$compile', '$templateCache', function($parse, $http, $compile, $templateCache)
    {
        var getTemplateUrl = function(type)
        {
            var templateUrl = '';

            switch (type)
            {
                case 1: // Table
                    templateUrl = 'modules/tpReport/directives/table-report.tpl.html';
                    break;
                case 0:
                    templateUrl = 'modules/tpReport/directives/default.tpl.html';
                    break;
                default:
                    templateUrl = '';
                    console.log("Type not defined for tpReport");
                    break;
            }

            return templateUrl;
        };

        var linker = function (scope, element, attrs)
        {

            scope.$watch('data', function(){
                var templateUrl = getTemplateUrl(scope.data[0].typeID);
                var data = $templateCache.get(templateUrl);
                element.html(data);
                $compile(element.contents())(scope);

            });



        };

        return {
            controller: 'tpReportCtrl',
            template: '<div>{{data}}</div>',
            // Remove all existing content of the directive.
            transclude: true,
            restrict: "E",
            scope: {
                data: '='
            },
            link: linker
        };
    }])
    ;

включить в свой html:

<tp-report data='data'></tp-report>

эта директива используется для динамической загрузки шаблонов отчетов на основе данных, полученных от сервера.

Он устанавливает часы на сферу.свойство data и всякий раз, когда оно обновляется (когда пользователи запрашивают новый набор данных с сервера), он загружает соответствующую директиву покажите данные.

вы должны сказать Angular, что ваша директива использует переменную scope:

вам нужно привязать некоторое свойство области к вашей директиве:

return {
    restrict: 'E',
    scope: {
      whatever: '='
    },
   ...
}

а то $watch это:

  $scope.$watch('whatever', function(value) {
    // do something with the new value
  });

относятся к угловая документация по директивам для получения дополнительной информации.

Я нашел гораздо лучшее решение:

app.directive('layout', function(){
    var settings = {
        restrict: 'E',
        transclude: true,
        templateUrl: function(element, attributes){
            var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
            return constants.pathLayouts + layoutName + '.html';
        }
    }
    return settings;
});

единственный недостаток я вижу в настоящее время является тот факт, что раскрываемый шаблоны получили в свои собственные рамки. Они получают значения от своих родителей, но вместо того, чтобы изменить значение в родителе, значение сохраняется в собственной, новой дочерней области. Чтобы избежать этого, я использую $parent.whatever вместо whatever.

пример:

<layout name="Default">
    <layout name="AnotherNestedLayout">
        <label>Whatever:</label>
        <input type="text" ng-model="$parent.whatever">
    </layout>
</layout>

вы должны следить за своим прицелом.

вот как вы можете сделать это:

<layout layoutId="myScope"></layout>

ваша директива должна выглядеть как

app.directive('layout', function($http, $compile){
    return {
        restrict: 'E',
        scope: {
            layoutId: "=layoutId"
        },
        link: function(scope, element, attributes) {
            var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
            $http.get(scope.constants.pathLayouts + layoutName + '.html')
                .success(function(layout){
                    var regexp = /^([\s\S]*?){{content}}([\s\S]*)$/g;
                    var result = regexp.exec(layout);

                    var templateWithLayout = result[1] + element.html() + result[2];
                    element.html($compile(templateWithLayout)(scope));
        });
    }
}

$scope.$watch('myScope',function(){
        //Do Whatever you want
    },true)

аналогично вы можете моделировать в своей директиве, поэтому, если модель обновляется автоматически, ваш метод часов обновит вашу директиву.

Я знаю эту старую тему, но в случае, если кто-нибудь найдет это, как я:

я использовал следующий код, когда мне нужна была моя директива для обновления значений при обновлении "родительской области". Пожалуйста, во что бы то ни стало поправьте меня, если я делаю что-то не так, как я все еще учусь угловой, но это сделало то, что мне нужно;

мы можем попробовать этот

$scope.$apply(function() {
    $scope.step1 = true;
    //scope.list2.length = 0;
});

http://jsfiddle.net/Etb9d/

простое решение состоит в том, чтобы сделать переменную scope объект. Затем получите доступ к содержимому с помощью {{ whatever-object.whatever-property }}. Переменная не обновляется, потому что JavaScript pass первобытное типа стоимостью. Тогда как объект передает ссылка что решает проблему.

Я не знаю, почему никто еще не предложил bindToController, который удаляет все эти уродливые scopes and $watches. Если вы используете Angular 1.4

ниже приведен пример DOM:

<div ng-app="app">
    <div ng-controller="MainCtrl as vm">
        {{ vm.name }}
        <foo-directive name="vm.name"></foo-directive>
        <button ng-click="vm.changeScopeValue()">
        changeScopeValue
        </button>
    </div>
</div>

следует controller код:

angular.module('app', []);

// main.js
function MainCtrl() {
    this.name = 'Vinoth Initial';
    this.changeScopeValue = function(){
        this.name = "Vinoth has Changed"
    }
}

angular
    .module('app')
    .controller('MainCtrl', MainCtrl);

// foo.js
function FooDirCtrl() {
}

function fooDirective() {
    return {
        restrict: 'E',
        scope: {
            name: '='
        },
        controller: 'FooDirCtrl',
        controllerAs: 'vm',
        template:'<div><input ng-model="name"></div>',
        bindToController: true
    };
}

angular
    .module('app')
    .directive('fooDirective', fooDirective)
    .controller('FooDirCtrl', FooDirCtrl);

Скрипка, чтобы играть вокруг, здесь мы меняем значение области в controller и автоматически directive updates on scope change. http://jsfiddle.net/spechackers/1ywL3fnq/

Comments

    Ничего не найдено.