2015-02-13 16 views
8

Ho un input di rendering direttiva basato su una configurazione inviata dal server. Tutto funziona alla grande eccetto per l'input 'select'. Non importa cosa provo, il modello ng non si aggiorna. Ho tagliato il mio codice molto per isolare il problema:ngModel non si aggiorna in selezionare

Javascript:

var myApp = angular.module('example', []); 

    myApp.factory('DynamicData', [function() { 
     return { 
      data: { 
       backup_frequency: 604800 
      } 
     }; 

    }]) 
    .directive('dynamicInput', 
     ['$compile', 'DynamicData', function($compile, DynamicData) { 

      /** 
      * Render the input 
      */ 
      var render = function render() { 
       var input = angular.element('<select class="form-control" ng-model="inner.backup_frequency" ng-options="option.value as option.title for option in options"></select>'); 
       return input; 
      }; 

      var getInput = function() 
      { 
       var input = render(); 
       return input ? input[0].outerHTML : ''; 
      }; 

      var getTemplate = function(){ 

       var template = '<div class="form-group">' + 
           'Select input ' + 
           '<div class="col-md-7">' + getInput() + '</div>' + 
          '</div>'; 
       return template; 
      }; 

      return { 
       restrict : 'E', 
       scope: { 
        content:'=content', 
       }, 

       link : function(scope, element, attrs) { 
        var template = getTemplate(); 

        scope.options = [ 
         {title: "Daily", value: 86400}, 
         {title: "Weekly", value: 604800}, 
         {title: "Monthly", value: 2678400}, 
         ]; 
        scope.inner = DynamicData.data; 
        console.info('inner data', scope.inner); 

        element.html(template); 
        element.replaceWith($compile(element.contents())(scope)); 


       } 
      }; 
     }]) 
     .controller('FormCtrl', ['DynamicData', '$scope', function (DynamicData, $scope){ 
     $scope.app = {}; 

     $scope.save = function save() { 
      $scope.value = DynamicData.data.backup_frequency; 
      console.info('DynamicData', DynamicData.data); 
     }; 
     }]); 

HTML:

<head> 
    <script data-require="[email protected]" data-semver="1.3.8" src="https://code.angularjs.org/1.3.8/angular.js"></script> 
    <link href="style.css" rel="stylesheet" /> 
    <script src="script.js"></script> 
    </head> 

    <body> 
    <h1>Dynamic Input :</h1> 
    <div data-ng-controller="FormCtrl"> 
     <dynamic-input class="form-group" content="app"></dynamic-input> 
     <span data-ng-bind="value"></span><br/> 
     <button class="btn btn-primary" ng-click="save()">Save</button> 
    </div> 
    </body> 

</html> 

Un plunker di lavoro è disponibile: http://plnkr.co/edit/mNBTJzZXjX6mLyPz6NCI?p=preview

Ti hai qualche idea sul perché il modello ng nella selezione non è aggiornato?

MODIFICA: Quello che voglio ottenere è l'aggiornamento della variabile "inner.backup_frequency" (il riferimento al mio oggetto dati restituito dal mio factory DynamicData). Come puoi vedere nel plunker, ogni volta che cambio l'opzione nella selezione, la variabile contenuta nel modello ng non viene aggiornata.

Grazie per il vostro tempo.

+0

vuoi di that'
'di essere diverso ogni volta che clicco. o il valore nelle opzioni selezionate per essere valido .. per favore spiega –

+0

Ciao, hai provato a recuperare l'evento on change sul select e in javascript set $ scope.varaible e than $ scope. $ apply() solo per vedere se ha qualcosa a che fare con l'elemento al di fuori del ciclo $ digest? – Andreas

+1

Vedere http://stackoverflow.com/a/22890796/446030 per quanto riguarda l'ordine di compilazione e la collocazione all'interno della dom. – JcT

risposta

3

L'ho risolto. Quello che dovevi fare era non sostituire il contenuto dell'elemento con il contenuto compilato, ma piuttosto sostituirlo con l'HTML grezzo e solo allora lo lo compila.

element.html(template); 
$compile(element.contents())(scope); 

Working Plunker.

EDIT: Ho modificato il codice per lavorare senza la direttiva:

Plunker without directive.

EDIT 2: anche una versione in cui si lavora con la direttiva, ma senza la compilazione:

Plunker.

+0

Ciao, grazie per la tua risposta, funziona.Tuttavia, mi piacerebbe davvero schiarire il mio DOM e rimuovere il tag HTML 'dynamic-input'. Qualche idea ? –

+0

@AlexandreNucera Sì, sembra che tutto ciò che la direttiva fa sia solo produrre codice HTML codificato, perché non usarlo e perdere la compilazione, ecc.? –

+0

Ok questo sembra fare il trucco: var e = $ compile (template) (scope); element.replaceWith (e); (Ti assegnerò la taglia domani, devo aspettare 21h) –

13

Avevo un problema simile e ho trovato che collegando direttamente ng-model a una variabile scope come sotto, la selezione della variabile scope in qualche modo non verrà aggiornata.

<select ng-model="selection" ng-options="option for option in options"> 

Invece, definire un modello di vista nella vostra ng-modello di portata e si legano a un campo di vista del modello il campo Modello vista verrà aggiornata.

<select ng-model="viewmodel.selection" ng-options="option for option in options"> 

Nel vostro controller, si dovrebbe fare questo:

app.controller('SomeCtrl', ['$scope' 
    function($scope) 
    { 
     $scope.viewmodel = {}; 
    }); 
+2

I take away che mi sono stati di grande aiuto: • il modello deve essere una * proprietà * su una variabile di ambito - NON una variabile di ambito • è meglio * non * assegna la proprietà della variabile scope in JS - basta fare riferimento in HTML e angular la creerà e aggiornarla – rushkeldon

+0

Ricorda: "L'ambito non è il modello, l'ambito ** si riferisce ** al modello" e "Ogni volta che si hai ng-model ** ci dev'essere un punto ** lì da qualche parte. Se non hai un punto, lo stai facendo male. "[Altro] (http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html) – dr3w

Problemi correlati