Il motivo è che poiché si sta creando un ambito isolato per la propria direttiva contenteditable
, la direttiva ng-model
sullo stesso elemento ottiene anche tale ambito isolato. Ciò significa che hai due diversi ambiti che non sono collegati tra loro, che hanno entrambi una proprietà form.userContent
che cambia separatamente. Credo che si potrebbe esemplificare che da questo codice:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
<script>
angular.module('myApp', []).controller('Ctrl', function($scope) {
})
.directive('contenteditable', function() {
return {
restrict : 'A', // only activate on element attribute
require : '?ngModel', // get a hold of NgModelController
scope: {},
link : function(scope, element, attrs, ngModel) {
if (!ngModel)
return; // do nothing if no ng-model
setInterval(function() {
if (angular.element('#contenteditable').scope().form)
console.log(angular.element('#contenteditable').scope().form.userContent);
if (angular.element('#textarea').scope().form)
console.log(angular.element('#textarea').scope().form.userContent);
}, 1000);
// Specify how UI should be updated
ngModel.$render = function() {
element.html(ngModel.$viewValue || '');
};
// Listen for change events to enable binding
element.bind('blur keyup change', function() {
scope.$apply(read);
});
read(); // initialize
// Write data to the model
function read() {
ngModel.$setViewValue(element.html());
}
}
};
});
</script>
</head>
<body ng-controller="Ctrl">
<form name="myForm">
<div ng-init="form.userContent"></div>
<div contenteditable name="myWidget" ng-model="form.userContent" id="contenteditable" required>Change me!</div>
<span ng-show="myForm.myWidget.$error.required">Required!</span>
<hr />
<textarea ng-model="form.userContent" id="textarea"></textarea>
</form>
</body>
</html>
Come vedrete nella vostra console, ci sono due ambiti diversi e form.userContent
su di loro cambiare separatamente, se si modifica il testo nella textarea o se si modifica la testo nel tuo divento contenteditable
Quindi scommetto che stai pensando "abbastanza con la spiegazione e mostrami una soluzione!". Bene, non c'è (a mia conoscenza) una soluzione carina per questo, ma ce n'è uno che funziona. Quello che vuoi fare è portare un riferimento del modello nel tuo ambito isolato e assicurarti che abbia lo stesso nome nel tuo ambito isolato come nell'ambito genitore.
Ecco quello che fai, invece di creare un ambito vuoto come questo:
...
scope: {}
...
si associa il modello come questo:
...
scope: {
model: '=ngModel'
}
....
Ora avete una proprietà model
sulla vostra portata isolata che è un riferimento a form.userContent
sull'ambito genitore. Ma ng-model
non è alla ricerca di una proprietà model
, sta cercando un form.userProperty
che ancora non esiste nel nostro ambito isolato. Quindi, per risolvere questo problema, aggiungiamo questo all'interno della nostra funzione di collegamento:
scope.$watch('model', function() {
scope.$eval(attrs.ngModel + ' = model');
});
scope.$watch(attrs.ngModel, function(val) {
scope.model = val;
});
Il primo orologio sincronizza i cambiamenti su form.userContent
che viene da fuori della nostra direttiva al nostro isolato form.userContent
, e il secondo orologio fa in modo che ci propaghiamo eventuali modifiche sul nostro form.userContent
isolato fino all'ambito principale.
Mi rendo conto che questa è una risposta lunga e forse non molto facile da seguire. Quindi sarei felice di chiarire qualsiasi cosa tu ritenga sia sfocata.
caso non 'element.html (ngModel $ viewValue ....) Essere' element.html ($ sce.getTrustedHtml (ngModel $. viewValue) ..) 'So che questo è quasi esattamente lo stesso dell'esempio di ng docs, ma ho appena scoperto che in questo modo ignora la protezione di xss altrimenti. – cirrus
@arun Puoi spiegare perché l'ambito isolato lo rende non funzionante? – geckob
Re @cirrus comment, mi sembra che per evitare XSS, ogni volta che qualcosa viene inserito nell'elemento dovrebbe prima essere disinfettato con $ sanitize (cioè non fidarsi dell'HTML). Qualcosa come element.html ($ sanitize (ngModel. $ ViewValue)) '. – Soferio