valor obtener con angularjs directive

obtener - AngularJS-Crea una directiva que usa ng-model



ng-value select (8)

Crear un ámbito de aislamiento no es deseable. Evitaría usar el atributo de alcance y hacer algo como esto. scope: true le da un nuevo alcance hijo pero no aísla. Luego use el análisis para apuntar una variable de alcance 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); } }; }]);

Estoy intentando crear una directiva que crearía 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 hay un error que indica que mi control no se está inicializando con el valor del campo de destino 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 ng-model="value" de la plantilla, esto parece estar funcionando bien. Sin embargo, mantendré esta pregunta abierta porque quiero volver a verificar que esta es la forma correcta de hacerlo.


Desde Angular 1.5 es posible utilizar Componentes. Los componentes son el camino a seguir y resuelve este problema fácilmente.

<myComponent data-ng-model="$ctrl.result"></myComponent> 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


En realidad es una lógica bastante buena, pero puedes simplificar un poco las cosas.

Directiva

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: ''<div class="some">'' + ''<input ng-model="myDirectiveVar"></div>'', 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); } }; });

Html con directiva

<body ng-controller="MainCtrl"> This scope value <input ng-model="name"> <my-directive my-directive-var="name"></my-directive> </body>

CSS

.some { border: 1px solid #cacaca; padding: 10px; }

Puedes verlo en acción con este Plunker .

Esto es lo que veo:

  • Entiendo por qué quiere usar ''ng-model'' pero en su caso no es necesario. ng-model es vincular elementos html existentes con un valor en el alcance. Ya que usted mismo está creando una directiva, está creando un "nuevo" elemento html, por lo que no necesita ng-model.

EDITAR Como mencionó Mark en su comentario, no hay razón para que no pueda usar el modelo ng, solo para mantener la convención.

  • Al crear explícitamente un alcance en su directiva (un alcance ''aislado''), el alcance de la directiva no puede acceder a la variable ''nombre'' en el alcance principal (por lo que creo que quería usar ng-model).
  • Eliminé ngModel de su directiva y lo reemplacé con un nombre personalizado que puede cambiar a lo que sea.
  • Lo que hace que todo siga funcionando es que el signo ''='' en el ámbito. Verifique la documentación docs bajo el encabezado ''alcance''.

En general, sus directivas deben usar el alcance aislado (que usted hizo correctamente) y usar el alcance de tipo ''='' si desea que un valor en su directiva se asigne siempre a un valor en el alcance primario.


Esta es una respuesta un poco tardía, pero encontré esta increíble post 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 manera, no se necesitan trucos: está usando el ng-model incorporado de Angular


No establecería el ngmodel a través de un atributo, puede especificarlo directamente en la plantilla:

template: ''<div class="some"><label>{{label}}</label><input data-ng-model="ngModel"></div>'',

plunker : http://plnkr.co/edit/9vtmnw?p=preview


Solo necesita ng-model cuando necesite acceder a $ viewValue o $ modelValue del modelo. Ver NgModelController . Y en ese caso, require: ''^ngModel'' .

Para el resto, ver respuesta de Roy .


Tomé un combo de todas las respuestas, y ahora tengo dos formas de hacerlo con el atributo ng-model:

  • Con un nuevo alcance que copia ngModel.
  • Con el mismo alcance que hace una compilación en enlace.

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: ''<div class="some"><label>{{label}}: <input ng-model="ngModel"></label></div>'', replace: true }; }); app.directive(''myDirectiveWithChildScope'', function($compile) { return { restrict: ''E'', scope: true, // Notice how label is visible in the scope template: ''<div class="some"><label>{{label}}: <input></label></div>'', 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: ''<div class="some"><label>{{$parent.label}}: <input></label></div>'', 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: ''<input class="some">'', replace: true }; }); app.directive(''myReplacedDirectiveChild'', function($compile) { return { restrict: ''E'', scope: true, template: ''<input class="some">'', replace: true }; }); app.directive(''myReplacedDirective'', function($compile) { return { restrict: ''E'', template: ''<input class="some">'', replace: true }; });

.some { border: 1px solid #cacaca; padding: 10px; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script> <div ng-app="model" ng-controller="MainCtrl"> This scope value <input ng-model="name">, label: "{{label}}" <ul> <li>With new isolate scope (label from parent): <my-directive-with-scope ng-model="name"></my-directive-with-scope> </li> <li>With new child scope: <my-directive-with-child-scope ng-model="name"></my-directive-with-child-scope> </li> <li>Same scope: <my-directive-without-scope ng-model="name"></my-directive-without-scope> </li> <li>Replaced element, isolate scope: <my-replaced-directive-isolate ng-model="name"></my-replaced-directive-isolate> </li> <li>Replaced element, child scope: <my-replaced-directive-child ng-model="name"></my-replaced-directive-child> </li> <li>Replaced element, same scope: <my-replaced-directive ng-model="name"></my-replaced-directive> </li> </ul> <p>Try typing in the child scope ones, they copy the value into the child scope which breaks the link with the parent scope. <p>Also notice how removing jQuery makes it so only the new-isolate-scope version works. <p>Finally, note that the replace+isolate scope only works in AngularJS >=1.2.0 </div>

No estoy seguro de que me guste la compilación en el momento del enlace. Sin embargo, si simplemente reemplaza el elemento por otro, no necesita hacerlo.

En general, prefiero el primero. Simplemente configure el alcance en {ngModel:"="} y establezca ng-model="ngModel" donde lo desee 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. Así que se reduce a:

  • ¿Está reemplazando un solo elemento? Simplemente cámbielo, deje solo el alcance, pero tenga en cuenta que reemplazar está en desuso para v2.0:

    app.directive(''myReplacedDirective'', function($compile) { return { restrict: ''E'', template: ''<input class="some">'', replace: true }; });

  • De lo contrario usa esto:

    app.directive(''myDirectiveWithScope'', function() { return { restrict: ''E'', scope: { ngModel: ''='', }, template: ''<div class="some"><input ng-model="ngModel"></div>'' }; });


no es tan complicado: en tu dirctive, usa un alias: scope:{alias:''=ngModel''}

.directive(''dateselect'', function () { return { restrict: ''E'', transclude: true, scope:{ bindModel:''=ngModel'' }, template:''<input ng-model="bindModel"/>'' }

en su html, usar como normal

<dateselect ng-model="birthday"></dateselect>