web-dev-qa-db-fra.com

Comment modifier la portée depuis une directive dans AngularJs

J'ai besoin de modifier un attribut de portée racine à partir d'un rappel à l'intérieur d'une directive. Mais la directive est dans une portée interne créée par une directive 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';
}

Violon: http://jsfiddle.net/nJ7FQ/

Mon objectif est de pouvoir afficher "Nouvelle valeur" dans la zone Sélectionnée. Comment puis-je accomplir ce que j'essaie de faire? Qu'est-ce que je fais mal?

D'ailleurs, comme j'essaye de faire un composant. Existe-t-il un moyen de faire de même mais avec une portée isolée?

26
Fernando

J'ai mis à jour le violon, je devais essentiellement aller au parent pour obtenir la bonne variable "sélectionnée", j'ai également utilisé l'isolate scope = pour obtenir une liaison bidirectionnelle entre la valeur transmise et le modèle interne.

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';
}

et le 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>

Mise à jour du violon pour utiliser votre lecture originale de la propriété à partir de l'attribut: http://jsfiddle.net/nJ7FQ/4/

20
shaunhusain

J'ai un peu amélioré le 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/

De cette façon, la valeur d'étendue que vous souhaitez modifier peut également être une propriété d'objet comme selected.foo Dans l'exemple. De plus, j'ai supprimé le paramètre scope et dit à la directive de toujours utiliser la portée parent. Et finalement, j'ai encapsulé le gestionnaire de clics dans le rappel $apply (Voir ici par exemple). Il vaudrait mieux, bien sûr, utiliser ngClick au lieu de element.bind().

15
stofl