2014-11-23 29 views
24

Ho un'app che sto costruendo con angolare, ho circa 8-10 viste da compilare. Tutte le viste hanno un piè di pagina condiviso, in base alla vista e un insieme di regole aziendali che ho bisogno di mostrare/nascondere condizionatamente parte del contenuto sul piè di pagina.AngularJS: ng-include e ng-controller

Così. Ho controller per ogni vista e quindi uno per il footer. Includo il layout del footer comune utilizzando ng-include, dove il codice html che sto includendo fa riferimento al controller footer nel controller ng.

Index.HTML

<body ng-controller="MainCtrl as vm"> 
    <p>Message from Main Controller '{{vm.mainMessage}}'</p> 
    <div ng-include="'commonFooter.html'"></div> 
</body> 

commonFooter.html

<div ng-controller="FooterCtrl as vm"> 
    <p>Message from Footer Controller '{{vm.message}}'</p> 
    <p ng-show="vm.showSomthing">Conditional footer Content</p> 
</div> 

voglio ciascun controller di vista per determinare lo stato del piè di pagina e se contenuto specifico è nascosto o meno. (shouldDisplaySomthingInFooter sotto)

app.controller('MainCtrl', function($scope) { 
    var vm = this; 
    vm.mainMessage= 'HEELO'; 
    vm.shouldDisplaySomthingInFooter = true; 
    window.console.log('Main scope id: ' + $scope.$id); 
}); 

allora avevo previsto che nel FooterController avrebbe raggiunto nuovamente dentro il controller principale e tirare fuori le impostazioni specifiche per abilitare/disabilitare i contenuti in base alle regole di business.

app.controller('FooterCtrl', function($scope) { 
    var vm = this; 
    vm.message = 'vm footer'; 

    window.console.log('Footer scope id: ' + $scope.$id); 
    window.console.log('Footer parent scope id: ' + $scope.$parent.$id); 
    window.console.log('Footer grandparent scope id: ' + $scope.$parent.$parent.$id); 
    window.console.log('Footer grandparent scope name: ' + $scope.$parent.$parent.mainMessage); 
    window.console.log('Footer grandparent scope condition: ' + $scope.$parent.$parent.shouldDisplaySomthingInFooter); 

    vm.showSomthing = false; //how to pull from parent scope to bind the ng-show to a value set in the parent from within a ng-include? 
}); 

ho questo esempio qui: http://plnkr.co/edit/ucI5Cu4jjPgZNUitY2w0?p=preview

Quello che sto trovando è che io quando arrivo nel campo di applicazione genitore di tirare fuori il contenuto si sta tornando come indefinito, e non sono sicuro perché.

Vedo che gli ambiti sono nidificati a livello di nonno controllando l'scopeid, credo che questo sia dovuto al fatto che il ng-include aggiunge un ulteriore livello di ambito al di sotto degli ambiti di visualizzazione. outout from console in attached example

Punti extra: Se non posso avere per usare l'oggetto $ portata e può attaccare con la var vm = this; modo di farlo che sarebbe preferibile. Ma i mendicanti non possono essere scelti :)

app.controller('MainCtrl', function($scope) { 
    var vm = this; 

Grazie mille in anticipo.

risposta

28

Se ambito il controller esterno come vm e il controller all'interno come foo, si può quindi separali facilmente e fai riferimento a vm withi n il controller interno.

Demo

HTML:

<body ng-controller="MainCtrl as vm"> 
    <p>Message from Main Controller '{{vm.mainMessage}}'</p> 
    <div ng-include="'commonFooter.html'"></div> 
</body> 

CommonFooter.html:

<div ng-controller="FooterCtrl as footer"> 
    <p>Message from Footer Controller '{{footer.message}}'</p> 
    <p ng-show="vm.shouldDisplaySomethingInFooter">Conditional footer Content</p> 
</div> 

app.js:

var app = angular.module('plunker', []); 

app.controller('MainCtrl', function() { 
    var self = this; 
    self.mainMessage = 'Hello world'; 
    self.shouldDisplaySomethingInFooter = true; 
}); 

app.controller('FooterCtrl', function() { 
    var self = this; 
    self.message = 'vm footer'; 
}); 

Nota: ho rinominato lo var vm = this in var self = this per chiarezza e per ridurre la confusione tra le visualizzazioni e i controller.

risultato atteso:

output showing the conditionally hidden\shown items

3

Hai frainteso il motivo per cui è utilizzato il controller come sintassi (see documentation). È solo un modo per esporre un determinato controller sull'ambito locale, in modo che sia possibile accedere alle sue proprietà da un modello. Quando si utilizza someController as vm in entrambi i modelli padre e piè di pagina, non si crea in qualche modo una connessione tra i controller o qualcosa del genere. Stai solo impostando una proprietà vm sull'ambito del footer, quindi quando la utilizzi nel modello del piè di pagina, stai accedendo al controller del piè di pagina (e hai bloccato la tua strada verso il controller principale).

Per ciò che si sta tentando di fare, in pratica non è necessario il sintonizzatore come sintassi. Inserisci correttamente i tuoi dati su $scope e lascia che la gerarchia dell'ambito faccia il resto per te.

nel controller genitore:

$scope.features.rock = true; 
$scope.features.roll = false; 

Nel modello footer

<p ng-show="features.rock">...</p> 
<p ng-show="features.roll">...</p> 

È ora possibile anche visualizzare e modificare la features dagli altri controllori (come i loro scopi sono discendenti di portata del controller genitore).

2

I giocherellava in giro con il vostro plunker, ma anche cambiato var vm = this;-$scope, quindi sono non riuscendo a guadagnare punti extra :-)

vorrei consigliare vivamente contro l'utilizzo di $scope.$parent esattamente per la ragione si mostra. Diverse direttive come ng-include, ng-show, ecc. Generano i propri ambiti.

Non hai alcun controllo se qualcuno in futuro cambia il tuo codice html e aggiunge ambiti, intenzionalmente o in altro modo.

Si consiglia di utilizzare le funzioni che risiedono su MainCtrl e di accedervi tramite ambiti ereditari.

Plunker

$scope.getShouldShow = function() { 
    return $scope.shouldDisplaySomthingInFooter; 
    }; 
    $scope.setShouldShow = function(val) { 
    $scope.shouldDisplaySomthingInFooter = val; 
    }; 

    $scope.getMainMessage = function() { 
    return $scope.mainMessage; 
    } 

e chiamarli:

<p ng-show="getShouldShow();">Conditional footer Content</p> 

E:

window.console.log('Footer grandparent scope name: ' + $scope.getMainMessage()); 
    window.console.log('Footer grandparent scope condition: ' + $scope.getShouldShow());