2013-06-19 23 views
10

Per favore fatemi sapere se avete bisogno di ulteriori informazioni o volete che chiarisca qualsiasi cosa. Ho provato molte cose diverse per capirlo ma non ho trovato una soluzione.AngularJS Associazione dati bidirezionale in direttive annidate

Sono relativamente nuovo su angularJS e sto cercando di creare un'app con diversi livelli di dati. Ho alcune informazioni utente di base memorizzate nell'ambito del corpo sul controller PageController. Poi ho un modulo di impostazioni che carica usando $ routeParams (con controller SettingsController) che include un paio di direttive personalizzate per scopi di template. Poiché le direttive sono nidificate, sto usando la transclusione per caricare la seconda all'interno della prima. Tutto sembra funzionare bene.

Il mio problema è che sto provando a fare riferimento al campo user.firstname dall'interno della direttiva più interna e voglio utilizzare l'associazione dati bidirezionale per consentire le modifiche apportate alla casella di testo per far sì che anche il valore dell'ambito di PageController cambi. So che molti tipi di problemi sono causati dall'uso delle primitive in ng-model, ma ho provato a inserire tutto all'interno di un oggetto extra in modo da attivare l'ereditarietà del prototipo inutilmente. Cosa sto facendo di sbagliato qui?

Ecco un codice JSFiddle del mio codice, ridotto il più possibile per isolare il problema. In questo esempio, se scrivo la casella di testo esterna, che è direttamente sull'ambito di PageController, modificherà la casella di testo interna fino a quando quella casella di testo non verrà modificata, su cui viene interrotta la connessione. Questo sembra proprio il problema dell'uso delle primitive come descritto in altre domande, ma non riesco a capire dove si trovi il problema.

HTML:

<body class="event-listing" ng-app="app" ng-controller="PageController"> 
    <div class="listing-event-wrap"> 
     <input type="text" ng-model="user.firstname" /> 
     <div ng-controller="SettingsController"> 
      <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}"> 
       <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" value="user.firstname"></div> 
      </section> 
     </div> 
    </div> 
</body> 

direttive angolari:

app.directive('formrow', function() { 
return { 
    scope: { 
      label: "@label", 
      type: "@type", 
      value: "=value" 
    }, 
    replace: true, 
    template: '<div class="form-row">' + 
      '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
      '<div class="form-entry" ng-switch on="type">' + 
       '<input type="text" ng-model="value" data-ng-switch-when="textInput" />' + 
      '</div>' + 
     '</div>' 
} 
}); 
app.directive('block', function() { 
return { 
    scope: { 
      title: "@title", 
      description: "@description" 
    }, 
    transclude: true, 
    replace: true, 
    template: '<div class="page-block">' + 
      '<h2 data-ng-show="title">{{title}}</h2>' + 
      '<p class="form-description" data-ng-show="description">{{description}}</p>' + 
      '<div class="block-inside" data-ng-transclude></div>' + 
      '</div>' 
} 
}); 

Controller angolari:

app.controller("PageController", function($scope) { 
    $scope.user = { 
     firstname: "John" 
    }; 
}); 
app.controller("SettingsController", function($scope) { 
    $scope.data = { 
     updateInfo: { 
      title: "Update Your Information", 
      description: "A description here", 
      labels: { 
       firstname: "First Name" 
      } 
     } 
    } 
}); 

risposta

9

Sono così rry per il codice precedente. Prova questo invece: http://jsfiddle.net/CxNc2/2/

Invece di passare il valore attuale, sto passando l'oggetto + un puntatore al valore corretto all'interno. Ho aggiunto 'refobject' qui:

<body class="event-listing" ng-app="app" ng-controller="PageController"> 
    <div class="listing-event-wrap"> 
     <input type="text" ng-model="user.firstname" /> 
     <div ng-controller="SettingsController"> 
      <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}"> 
       <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" refobj='user' value="firstname"></div> 
      </section> 
     </div> 
    </div> 
</body> 

e ho aggiunto refobj + valore qui:

app.directive('formrow', function() { 
    return { 
     scope: { 
      label: "@label", 
      type: "@type", 
      value: "@value", 
      refobj: "=" 
     }, 
     replace: true, 
     template: '<div class="form-row">' + 
      '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
      '<div class="form-entry" ng-switch on="type">' + 
     '<input type="text" ng-model="refobj[value]" data-ng-switch-when="textInput" />' + 
      '</div>' + 
     '</div>' 
    } 
+0

Grazie per una risposta così rapida! Ho provato il violino ma sembra fare la stessa cosa di quello che ho postato. Qual è l'obiettivo di cambiarlo in una funzione isolare l'ambito? – princjef

+0

Ho aggiunto refobj quindi non è necessario chiamare 'firstname' all'interno della direttiva in quanto sono sicuro che vuoi essere generico. – Nir

+0

È davvero intelligente! Non avevo pensato di usare la notazione dell'array invece del punto. Questo funzionerà per i miei bisogni. Grazie! – princjef

8

Dal momento che la casella di testo nella direttiva utilizza una primitiva, invece di un oggetto per il suo modello (ng-model="value" piuttosto che ng-model="someobj.somevalue"), il suo modello viene creato solo sull'ambito locale e il genitore non ha accesso ad esso.

La correzione è quello di definire il modello di direttiva di testo utilizzando il dot rule come proprietà dell'oggetto:

ng-model="value.firstname" 

poi passare il tutto user oggetto nella direttiva invece che solo la proprietà primitiva:

<div formrow ... value="user"></div> 

Here is a demo

+0

Oh capisco dove ho sbagliato. Grazie per l'intuizione – princjef

+0

Hey, ho semplificato la demo solo per vedere le cose più chiare. Sembra che funzioni con oggetti complessi, ma non con proprietà semplici ... [Ecco la versione aggiornata] (http://jsfiddle.net/BXRnM/4/). Riesci a vedere perché? – Dmitry

+0

@Dmitry L'esempio della proprietà semplice reintroduce l'errore dell'OP.Per dirla in breve, l'ereditarietà dell'ambito angolare _richiede oggetti piuttosto che semplici variabili primitive_. Questa è una conseguenza diretta dell'eredità prototipale in JavaScript. Puoi dare un'occhiata a [[questa risposta] (http://stackoverflow.com/questions/16928341/update-parent-scope-variable/16929117#16929117)] Ho dato altrove per vedere un altro esempio o controllare [[questo Q & A] (http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs)] per una spiegazione più dettagliata. – sh0ber

0

Il problema è s causato da ng-switch, dal doc Understanding scope da git.

l'ereditarietà del campo di applicazione ng-switch funziona proprio come ng-include. Pertanto, se è necessario il bind dei dati a 2 vie in una primitiva nell'ambito genitore, utilizzare $ parent oppure modificare il modello in modo che sia un oggetto e quindi associare a una proprietà di tale oggetto . Ciò consentirà di evitare l'occultamento/ombreggiamento del campo figlio per le proprietà dello scope principale .

quindi se si digita del testo nella casella di testo. di seguito codice verrà eseguito per l'ambito ng-switch.

$scope.value="the text you typed"

Così non consulterà la catena di prototipi per la ricerca value .questo sarà creata una nuova proprietà per ng-switch ambito.

Come testimoniarlo?

Se si modifica value in $parent.value. tutto funzionerà bene. perché nel ng-switch per il tipo primitivo (angularjs riconoscerebbe il value come tipo primitivo se non c'è alcun punto) $parent farà riferimento all'ambito della direttiva formrow.

Provare a rimuovere il ng-switch o fare come dice il documento. il problema sparirà.

E, cosa più importante, il documento ci consiglia di utilizzare sempre un punto . per fare riferimento al modello quando si applica una rilegatura bidirezionale.

Se ho detto qualcosa di sbagliato. Per favore, correggimi gentilmente e fallo bene. Grazie.

Problemi correlati