2015-05-10 8 views
9

Ho un oggetto data nel MainCtrl. Questo oggetto viene utilizzato per passare i dati alle direttive first-directive e second-directive. L'associazione di due dati è necessaria in entrambi i casi.Passare param a direttive nidificate con ambito isolato

Per first-directive, io passare l'oggetto completo data ma per second-directive voglio passare numbers oggetto (scope.numbers = scope.dataFirst.numbers).

Il problema:

Quando faccio <div second-directive="dataFirst.numbers"></div>, e verifico se dataSecond è un oggetto, restituisce true.

Ma quando faccio <div second-directive="numbers"></div> e controllo se dataSecond è un oggetto, restituisce false.

In entrambi i casi se si fa console.log(scope) viene mostrata la proprietà scope.dataSecond.

La domanda:

Perché si verifica e qual è il modo corretto per passare params alle direttive?

MODIFICA: L'idea sta facendo direttive riutilizzabili e questo implica che non possono dipendere da altre direttive.

angular.module('app',[]) 
 

 
.controller('MainCtrl', function($scope) { 
 
    $scope.data = { 
 
    numbers: { 
 
     n1: 'one', 
 
     n2: 'two' 
 
    }, 
 
    letters: { 
 
     a: 'A', 
 
     b: 'B' 
 
    } 
 
    } 
 
}) 
 

 
.directive('firstDirective', function() { 
 
    return { 
 
    template: '<div class="first-directive">\ 
 
     <h2>First Directive</h2>\ 
 
     {{dataFirst}}\ 
 
     <div second-directive="dataFirst.numbers"></div>\ 
 
     <div second-directive="numbers"></div>\ 
 
     </div>', 
 
    replace: true, 
 
    restrict: 'A', 
 
    scope: { 
 
     dataFirst: '=firstDirective' 
 
    }, 
 
    link: function postLink(scope, element, attrs) { 
 
     console.log('first directive') 
 
     console.log(scope) 
 
     scope.numbers = scope.dataFirst.numbers; 
 
    } 
 
    }; 
 
}) 
 

 
.directive('secondDirective', function() { 
 
    return { 
 
    template: '<div class="second-directive">\ 
 
     <h2>Second Directive</h2>\ 
 
     {{dataSecond}}\ 
 
     <div class="is-obj">is an object: {{isObj}}</div>\ 
 
     </div>', 
 
    replace: true, 
 
    restrict: 'A', 
 
    scope: { 
 
     dataSecond: '=secondDirective' 
 
    }, 
 
    link: function postLink(scope, element, attrs) { 
 
     console.log('second directive'); 
 
     console.log(scope) 
 
     
 
     // <div second-directive="XXXX"></div> 
 
     // if 'numbers' returns undefined 
 
     // if 'dataFirst.numbers' returns the object 
 
     console.log(scope.dataSecond); 
 
     
 
     scope.isObj = false; 
 
     
 
     if(angular.isObject(scope.dataSecond)){ 
 
     scope.isObj = true; 
 
     } 
 
    } 
 
    }; 
 
});
h2 { 
 
    padding: 0; 
 
    margin: 0; 
 
} 
 

 
.first-directive { 
 
    background: #98FFDA; 
 
    color: black; 
 
    padding: 10px; 
 
} 
 

 
.second-directive { 
 
    background: #FFA763; 
 
    color: white; 
 
    padding: 10px; 
 
} 
 

 
.is-obj { 
 
    background: blue; 
 
}
<!DOCTYPE html> 
 
<html ng-app="app"> 
 

 
    <head> 
 
    <meta charset="utf-8" /> 
 
    <title>AngularJS Plunker</title> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
    </head> 
 

 
    <body ng-controller="MainCtrl"> 
 
    <h2>MainCtrl</h2> 
 
    {{data}} 
 

 
    <div first-directive="data"> 
 
    </div> 
 

 
    <div second-directive="data"> 
 
    </div> 
 
    </body> 
 

 
</html>

risposta

10

lo ripeto quello che altri prima di me ha detto - che la funzione di linkfirstDirective è una funzione diposta -link che corre dopo la funzione link di secondDirective, e quindi scope.numbers non è ancora assegnato l'oggetto scope.dataFirst.numbers.

Tuttavia, una soluzione che accoppia strettamente due direttive tramite require mi sembra non ottimale.

Invece, per assicurarsi che una proprietà ambito sia correttamente assegnato nel genitore prima di direttive/bambino interiore correre (come secondDirective, in questo caso) è quello di utilizzare un pre funzione -link nel firstDirective (invece di una posta -link)

link: { 
    pre: function prelink(scope){ 
     console.log('first directive') 
     console.log(scope) 
     scope.numbers = scope.dataFirst.numbers; 
    } 
} 

Demo

9

La mia soluzione a questo sarebbe quella di avere la seconda direttiva ereditano l'attributo dell'oggetto dati dal primo direttiva.

angular.module('app', []) 
 

 
.controller('MainCtrl', function($scope) { 
 
    $scope.data = { 
 
    numbers: { 
 
     n1: 'one', 
 
     n2: 'two' 
 
    }, 
 
    letters: { 
 
     a: 'A', 
 
     b: 'B' 
 
    } 
 
    } 
 
}) 
 

 
.directive('firstDirective', function() { 
 
    return { 
 
    template: '<div class="first-directive">\ 
 
     <h2>First Directive</h2>\ 
 
     {{dataFirst}}\ 
 
     <div second-directive></div>\ 
 
     <div second-directive></div>\ 
 
     </div>', 
 
    replace: true, 
 
    restrict: 'A', 
 
    scope: { 
 
     dataFirst: '=firstDirective' 
 
    }, 
 
    controller: function firstDirectiveController($scope) { 
 
     return $scope; 
 
    }, 
 
    link: function postLink(scope, element, attrs) { 
 
     console.log('first directive') 
 
     console.log(scope) 
 
     scope.numbers = scope.dataFirst.numbers; 
 
    } 
 
    }; 
 
}) 
 

 
.directive('secondDirective', function() { 
 
    return { 
 
    template: '<div class="second-directive">\ 
 
     <h2>Second Directive</h2>\ 
 
     {{dataSecond}}\ 
 
     <div class="is-obj">is an object: {{isObj}}</div>\ 
 
     </div>', 
 
    replace: true, 
 
    require: '^firstDirective', 
 
    link: function postLink(scope, iElement, iAttrs, firstDirectiveController) { 
 
     console.log('second directive'); 
 
     console.log(firstDirectiveController.dataFirst.numbers); 
 
     
 
     scope.dataSecond = firstDirectiveController.dataFirst.numbers; 
 

 
     scope.isObj = false; 
 

 
     if (angular.isObject(scope.dataSecond)) { 
 
     scope.isObj = true; 
 
     } 
 
    } 
 
    }; 
 
}); 
 
h2 { 
 
    padding: 0; 
 
    margin: 0; 
 
} 
 

 
.first-directive { 
 
    background: #98FFDA; 
 
    color: black; 
 
    padding: 10px; 
 
} 
 

 
.second-directive { 
 
    background: #FFA763; 
 
    color: white; 
 
    padding: 10px; 
 
} 
 

 
.is-obj { 
 
    background: blue; 
 
}

 
<!DOCTYPE html> 
 
<html ng-app="app"> 
 

 
    <head> 
 
    <meta charset="utf-8" /> 
 
    <title>AngularJS Plunker</title> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
     <link rel="stylesheet" href="style.css"> 
 
    <script src="script.js"></script> 
 
    </head> 
 

 
    <body ng-controller="MainCtrl"> 
 
    <h2>MainCtrl</h2> 
 
    {{data}} 
 

 
    <div first-directive="data"> 
 
    </div> 
 
    </body> 
 

 
</html>

+2

E 'una buona risposta se si conosce l'ordine nidificato delle direttive nel codice HTML. La mia idea è di creare componenti riutilizzabili (come i dropdown) e questo implica che non si conosce l'ordine. Ad esempio, se provi a mettere la 'seconda direttiva 'nel' ', non funziona perché ha bisogno della' prima direttiva'. Grazie :) – cespon

+2

Questa soluzione funziona sicuramente (anche se accoppia strettamente le due direttive inutilmente), ma una buona risposta dovrebbe essere più che un semplice codice. –