Estoy tratando de 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
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
This scope value <input ng-model="name">
<my-directive ng-model="name"></my-directive>
</body>
</html>
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: '<div class="some"><label for="{{id}}">{{label}}</label>' +
'<input id="{{id}}" ng-model="value"></div>',
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 existe un error de que mi control no se está inicializando con el valor del campo objetivo del modelo ng.
Aquí hay un Plunker del código anterior: http://plnkr.co/edit/IvrDbJ
¿Cuál es la forma correcta de manejar esto?
EDITAR : después de eliminar la ng-model="value"
plantilla, parece que funciona bien. Sin embargo, mantendré esta pregunta abierta porque quiero verificar que esta sea la forma correcta de hacerlo.
scope
y lo configurascope: false
? ¿Cómo unirseng-model
en ese caso?Respuestas:
EDITAR : Esta respuesta es antigua y probablemente desactualizada. Solo un aviso para que no desvíe a la gente. Ya no uso Angular, así que no estoy en una buena posición para hacer mejoras.
En realidad, es una lógica bastante buena, pero puedes simplificar un poco las cosas.
Directiva
HTML con directiva
CSS
Puedes verlo en acción con este Plunker .
Esto es lo que veo:
EDITAR Como mencionó Mark en su comentario, no hay razón para que no pueda usar ng-model, solo para mantener la convención.
En general, sus directivas deben usar el alcance aislado (lo cual hizo correctamente) y usar el alcance de tipo '=' si desea que un valor en su directiva siempre se asigne a un valor en el alcance primario.
fuente
contenteditable
ejemplos de directivas en la documentación de Angular - página de formularios , página NgModelController - ambos usan ng-model. Y la página ngModelController dice que este controlador está "destinado a ser extendido por otras directivas".hg-model
(y no el problema del acoplamiento, IMO). De esta forma, el contexto de datos siempre usa ng-model, ya sea una<input>
directiva personalizada o una, lo que simplifica la sobrecarga cognitiva para el escritor de HTML. Es decir, ahorra que el escritor HTML tenga que averiguar cuál es el nombremy-directive-var
de cada directiva, especialmente porque no hay autocompletado para ayudarlo.ng-model-options
ninguna de las otras cosas del modelo, ¿verdad?Tomé un combo de todas las respuestas, y ahora tengo dos formas de hacerlo con el atributo ng-model:
Mostrar fragmento de código
No estoy seguro de que me guste la compilación en el momento del enlace. Sin embargo, si solo está reemplazando el elemento con otro, no necesita hacerlo.
En general, prefiero el primero. Simplemente establezca el alcance
{ngModel:"="}
y establezcang-model="ngModel"
dónde lo quiere en su plantilla.Actualización : introduje el fragmento de código y lo actualicé para Angular v1.2. Resulta que el alcance de aislamiento es aún mejor, especialmente cuando no se usa jQuery. Entonces se reduce a:
¿Está reemplazando un solo elemento? Simplemente reemplácelo, deje el alcance solo, pero tenga en cuenta que el reemplazo está en desuso para v2.0:
De lo contrario, use esto:
fuente
ng-model
en un ámbito aislado?no es tan complicado: en tu directorio, usa un alias:
scope:{alias:'=ngModel'}
en tu html, úsalo normalmente
fuente
Solo necesita ng-model cuando necesita acceder a $ viewValue o $ modelValue del modelo. Ver NgModelController . Y en ese caso, lo usarías
require: '^ngModel'
.Para el resto, vea la respuesta de Roys .
fuente
^
debería estar allí solo si el modelo ng se aplica en un elemento padreEsta es una respuesta un poco tardía, pero encontré esta increíble publicación sobre
NgModelController
, que creo que es exactamente lo que estabas buscando.TL; DR : puede usar
require: 'ngModel'
y luego agregarNgModelController
a su función de enlace:De esta manera, no se necesitan hacks: estás utilizando el Angular incorporado
ng-model
fuente
No establecería el ngmodel a través de un atributo, puede especificarlo directamente en la plantilla:
plunker : http://plnkr.co/edit/9vtmnw?p=preview
fuente
Desde Angular 1.5 es posible usar componentes. Los componentes son el camino a seguir y resuelve este problema fácilmente.
Dentro de YourController, todo lo que necesita hacer es:
fuente
input ng-model="$ctrl.ngModel"
y se sincronizará con $ ctrl.result también.Crear un alcance aislado no es deseable. Evitaría usar el atributo de alcance y hacer algo como esto. alcance: verdadero le da un nuevo alcance secundario pero no aislado. Luego use parse para apuntar una variable de alcance local al mismo objeto que el usuario ha suministrado al atributo ngModel.
fuente