Как изменить область действия из директивы в AngularJs

Мне нужно изменить атрибут корневой области внутри обратного вызова внутри директивы. Но директива находится во внутренней области, созданной директивой switch.

HTML

<div ng-app="app" ng-controller='AppController'>
    <p>Selected: {{ selected }}</p>
    <div ng-switch on="selected">
        <div ng-switch-default>
            <p>Item: {{ selected }}</p>
            <custom-tag selected-item="selected" />
        </div>
        <div ng-switch-when="New value">
            <p>Worked</p>
        </div>
    </div>
</div>

JavaScript

angular.module('app', [])    
    .directive("customTag", [function () {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope[attrs.selectedItem] = "New value";
                scope.$apply();
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = 'Old value';
}

Скрипт: http://jsfiddle.net/nJ7FQ/

Моя цель - иметь возможность отображать «Новое значение» в выбранной области. Как я могу выполнить то, что я пытаюсь сделать? Что я делаю не так?

Кроме того, поскольку я пытаюсь сделать компонент. Есть ли способ сделать то же самое, но с изолированной областью?


person Fernando    schedule 10.07.2013    source источник


Ответы (2)


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

http://jsfiddle.net/nJ7FQ/2/

angular.module('app', [])

    .directive("customTag", [function () {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",
        scope: {model:'='},

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope.model[attrs.selectedItem] = "New value";
                scope.$apply();
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = 'Old value';
}

и HTML

<div ng-app="app" ng-controller='AppController'>
    <p>Selected: {{ selected }}</p>
    <div ng-switch on="selected">
        <div ng-switch-default>
            <p>Item: {{ selected }}</p>
            <custom-tag selected-item="selected" model="$parent" />
        </div>
        <div ng-switch-when="New value">
            <p>Worked</p>
        </div>
    </div>
</div>

Обновлена ​​скрипка, чтобы использовать исходное чтение свойства из атрибута: http://jsfiddle.net/nJ7FQ/4/

person shaunhusain    schedule 10.07.2013
comment
Мне больше понравилось ваше первое решение (jsfiddle.net/nJ7FQ/2). Оно как-то кажется чище. Но почему я должен использовать $parent.selected, когда, насколько я понимаю, дочерние области наследуют все свойства родителя? - person Fernando; 10.07.2013
comment
Что ж, если вы измените выбранный на тот, который был унаследован, он не изменит выбранную переменную родительской области, перейдя к родителю и изменив переменную в этой области, а затем, когда прочитано дочернее выбранное значение, оно переходит к родителю . Если вы измените выбранное свойство дочерней области, оно станет новым свойством дочерней области и больше не будет наследоваться. (Я знаю, что это сбивает с толку) Это прототипическое наследование Javascript, если вы хотите его найти в Google. - person shaunhusain; 10.07.2013
comment
Это не работает. установка scope:'=' в директиве делает scope неопределенным. - person dopatraman; 26.11.2014
comment
@dopatraman, да, узнав больше об angular за последний год, я бы не согласился со своим собственным ответом здесь, в котором говорилось, что я не уверен, что проблема, с которой вы сталкиваетесь, связана с проблемами, которые у меня были бы с этим методом . Если вы разместили еще один вопрос SO с вашим кодом и проблемой, свяжите его здесь, и я посмотрю. - person shaunhusain; 26.11.2014
comment
Обратите внимание, что необходимо использовать link; эта альтернатива, точно такая же, как у shaunhusain, за исключением использования controller, не работает. Предположительно, это связано с тем, что область изоляции устанавливается вовремя только для функции link, а не для функции controller. - person The Red Pea; 07.11.2016

Я немного улучшил jsfiddle:

angular.module('app', [])

    .directive("customTag", ['$parse', function ($parse) {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope.$apply(function () {
                    $parse(attrs.selectedItem).assign(scope.$parent, "New value");
                });
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = { 'foo': 'Old value' };
}

http://jsfiddle.net/nJ7FQ/15/

Таким образом, значение области, которое вы хотите изменить, также может быть свойством объекта, таким как selected.foo в примере. Кроме того, я удалил параметр области и сказал директиве всегда использовать родительскую область. И, наконец, я включил обработчик кликов в обратный вызов $apply (см., например, здесь). ). Лучше было бы, конечно, использовать ngClick вместо element.bind().

person stofl    schedule 12.01.2014
comment
БИНГО! Хорошее решение для назначения родительской области. Идеально подходит для чего-то вроде модальных окон - person saike; 20.01.2016