Intento crear una directiva que cree un campo de entrada con el mismo modelo ng que el elemento que crea la directiva.
Esto es lo que se me ocurrió hasta ahora:
HTML
AngularJS Plunker document.write(""); This scope value
JavaScript
var app = angular.module('plunker', []); app.controller('MainCtrl', function($scope) { $scope.name = "Felipe"; }); app.directive('myDirective', function($compile) { return { restrict: 'E', scope: { ngModel: '=' }, template: '' + '', replace: true, require: 'ngModel', link: function($scope, elem, attr, ctrl) { $scope.label = attr.ngModel; $scope.id = attr.ngModel; console.debug(attr.ngModel); console.debug($scope.$parent.$eval(attr.ngModel)); var textField = $('input', elem). attr('ng-model', attr.ngModel). val($scope.$parent.$eval(attr.ngModel)); $compile(textField)($scope.$parent); } }; });
Sin embargo, no estoy seguro de que esta sea la forma correcta de manejar este escenario, y hay un error que indica que mi control no se inicializa con el valor del campo objective ng-model.
Aquí hay un Plunker del código de arriba: http://plnkr.co/edit/IvrDbJ
¿Cuál es la forma correcta de manejar esto?
EDITAR : Después de eliminar el ng-model="value"
de la plantilla, parece que funciona bien. Sin embargo, mantendré abierta esta pregunta porque quiero verificar que esta sea la manera correcta de hacerlo.
En realidad es bastante buena lógica, pero puedes simplificar las cosas un poco.
var app = angular.module('plunker', []); app.controller('MainCtrl', function($scope) { $scope.model = { name: 'World' }; $scope.name = "Felipe"; }); app.directive('myDirective', function($compile) { return { restrict: 'AE', //attribute or element scope: { myDirectiveVar: '=', //bindAttr: '=' }, template: '' + '', replace: true, //require: 'ngModel', link: function($scope, elem, attr, ctrl) { console.debug($scope); //var textField = $('input', elem).attr('ng-model', 'myDirectiveVar'); // $compile(textField)($scope.$parent); } }; });
This scope value
.some { border: 1px solid #cacaca; padding: 10px; }
Puedes verlo en acción con este Plunker .
Esto es lo que veo:
EDITAR Como menciona Mark en su comentario, no hay ninguna razón por la que no puedas usar ng-model, solo para seguir con la convención.
En general, sus directivas deberían usar el scope aislado (que lo hizo correctamente) y usar el scope del tipo ‘=’ si desea que un valor en su directiva se corresponda siempre con un valor en el ámbito principal.
Tomé un combo de todas las respuestas, y ahora tengo dos formas de hacerlo con el atributo ng-model:
var app = angular.module('model', []); app.controller('MainCtrl', function($scope) { $scope.name = "Felipe"; $scope.label = "The Label"; }); app.directive('myDirectiveWithScope', function() { return { restrict: 'E', scope: { ngModel: '=', }, // Notice how label isn't copied template: '', replace: true }; }); app.directive('myDirectiveWithChildScope', function($compile) { return { restrict: 'E', scope: true, // Notice how label is visible in the scope template: '', replace: true, link: function ($scope, element) { // element will be the div which gets the ng-model on the original directive var model = element.attr('ng-model'); $('input',element).attr('ng-model', model); return $compile(element)($scope); } }; }); app.directive('myDirectiveWithoutScope', function($compile) { return { restrict: 'E', template: '', replace: true, link: function ($scope, element) { // element will be the div which gets the ng-model on the original directive var model = element.attr('ng-model'); return $compile($('input',element).attr('ng-model', model))($scope); } }; }); app.directive('myReplacedDirectiveIsolate', function($compile) { return { restrict: 'E', scope: {}, template: '', replace: true }; }); app.directive('myReplacedDirectiveChild', function($compile) { return { restrict: 'E', scope: true, template: '', replace: true }; }); app.directive('myReplacedDirective', function($compile) { return { restrict: 'E', template: '', replace: true }; });
.some { border: 1px solid #cacaca; padding: 10px; }
This scope value , label: "{{label}}" - With new isolate scope (label from parent):
- With new child scope:
- Same scope:
- Replaced element, isolate scope:
- Replaced element, child scope:
- Replaced element, same scope:
Try typing in the child scope ones, they copy the value into the child scope which breaks the link with the parent scope.
Also notice how removing jQuery makes it so only the new-isolate-scope version works.
Finally, note that the replace+isolate scope only works in AngularJS >=1.2.0
no es tan complicado: en tu directorio, usa un alias: scope:{alias:'=ngModel'}
.directive('dateselect', function () { return { restrict: 'E', transclude: true, scope:{ bindModel:'=ngModel' }, template:'' }
en tu html, usa como siempre
Solo necesita ng-model cuando necesite acceder a $ viewValue o $ modelValue del modelo. Ver NgModelController . Y en ese caso, require: '^ngModel'
.
Por lo demás, ver la respuesta de Roys .
Esta es una respuesta tardía, pero encontré esta publicación increíble sobre NgModelController
, que creo que es exactamente lo que buscabas.
TL; DR : puede usar require: 'ngModel'
y luego agregue NgModelController
a su función de enlace:
link: function(scope, iElement, iAttrs, ngModelCtrl) { //TODO }
De esta forma, no es necesario realizar ningún corte: está utilizando el ng-model
incorporado de Angular
No establecería el ngmodel a través de un atributo, puede especificarlo directamente en la plantilla:
template: '',
plunker : http://plnkr.co/edit/9vtmnw?p=preview
Desde Angular 1.5 es posible usar componentes. Los componentes son el camino a seguir y resuelve este problema fácilmente.
app.component("myComponent", { templateUrl: "yourTemplate.html", controller: YourController, bindings: { ngModel: "=" } });
Dentro de YourController todo lo que necesitas hacer es:
this.ngModel = "x"; //$scope.$apply("$ctrl.ngModel"); if needed
Crear un scope aislado no es deseable. Evitaría usar el atributo de scope y hacer algo como esto. scope: true le da un nuevo scope de hijo pero no está aislado. A continuación, utilice el análisis para señalar una variable de ámbito local al mismo objeto que el usuario ha proporcionado al atributo ngModel.
app.directive('myDir', ['$parse', function ($parse) { return { restrict: 'EA', scope: true, link: function (scope, elem, attrs) { if(!attrs.ngModel) {return;} var model = $parse(attrs.ngModel); scope.model = model(scope); } }; }]);