una script por pasar parametros pagina otro otra funciones funcion entre directivas desde datos javascript angularjs angularjs-scope angularjs-ng-repeat angular-directive

por - pasar variables entre funciones javascript



¿Cómo se puede pasar un argumento a una directiva sin sobreescribir el alcance de los padres? (9)

Necesito crear una directiva que actúe sobre las celdas de la tabla donde se representan las filas de la tabla usando ng-repeat . Para ello he dependido en parte de esta respuesta a una pregunta titulada "Llamar a una función cuando ng-repeat ha terminado". Sin embargo, a diferencia de las preguntas y respuestas, necesito pasar un argumento a mi directiva, y para esto he confiado en parte en esta respuesta (a una pregunta titulada "Angularjs - Pase el argumento a la directiva").

Entonces, en mi caso, agregué fixed-column-tooltip para mi directiva, y columnselector como argumento para el <tr> siguiente manera:

<tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch">

Pero cuando por la segunda respuesta, agregué lo que aprendí es un "alcance aislado" a mi directiva, ya no tuve acceso al alcance original necesario según la primera respuesta:

''use strict''; angular.module(''cmt.cases.directives'') .directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', scope: { columnselector: ''@'' }, link: function (scope, element, attr) { if (scope.$last === true) { //undefined because not operating on original scope ...

¿Hay alguna manera de mantener el acceso al alcance original, pero también tener acceso al argumento columnselector ?


De acuerdo, primero que nada porque estás usando un alcance aislado no significa que no puedas acceder a algo en el ámbito principal. Un alcance aislado está diseñado para limitar lo que obtienes por defecto, pero puedes especificar lo que quieras desde el alcance principal. La forma correcta de hacerlo sería configurar un enlace bidireccional en su directiva utilizando "parentScopeVariable: ''=''". Perdona el formato horrible que estoy en el móvil y quiero irme a la cama :-).

Entonces sí, como dijiste, también puedes usar el parámetro "attrs", seguro. Incluso hay maneras $ eval difíciles de configurar cosas en el alcance principal que solo se pasan como atributos. No puede tener más de una directiva con un alcance aislado en un elemento / componente dado de todos modos, por lo que realmente debe tener cuidado cuando usa el alcance aislado. Sin embargo, definitivamente se presta a un diseño limpio porque tienes que ser deliberado sobre lo que usas en tu directiva. Ser punto, confiar en Attrs es bueno y necesario a veces, en mi mente. Es cierto que se siente un poco hackish o lo que sea (el código de pensamiento huele mal), pero no creo que haya un caso fuerte para eso.

Por último, he pasado mucho tiempo en el sitio de doc. Angular API y hay un montón de cosas buenas allí. Hay una referencia de directiva bastante buena en la página de servicio $ compile. Nuevamente, móvil, lo siento. Si estuviera en una computadora completa, haría buenos bloques de código y vincularía el ref la directiva, lo siento :-). Un google rápido y lo encontrarás.

Por lo tanto, definitivamente puede usar un alcance aislado y hay formas de pasar llamadas a una directiva, pasar directivas de funciones de directivas, volver a un controlador, vincular datos de dos vías, etc. El alcance aislado es ideal para todo eso pero no parece que intentas hacer algo demasiado complejo.


En el marco angular en una plantilla HTML, puede acceder al alcance principal.

Por ejemplo:

<div ng-model="$parent.$parent.theModel"></div>

Esto funciona cuando crea nuevos ámbitos dentro de la plantilla, como por ejemplo ng-repeat y similares. En teoría, puede usar esto para acceder al alcance principal que desea usar.


tal vez un poco feo, pero en funcionamiento: obtenga el elemento DOM de su directiva actual, retroceda hasta su elemento principal, conviértalo en un elemento angular, llame a la función incorporada scope (), p. ej.

link: function (scope, elem) { var parentScope = angular.element ($(elem).parent()).scope(); console.log (parentScope) }


Tocar el alcance principal podría no ser la mejor idea (me refiero a que no es una forma angular de acceder a la capa diferente), es mejor tener algunos scope.models adicionales. De todos modos aquí hay una demostración de trabajo simple.

angular.module(''app'', []) .controller(''ctrl'', function($scope){ $scope.trDataWatch = [''item1'', ''item2'', ''item3'']; $scope.state = ''unrendered''; $scope.$on(''ngRepeatFinished'', function(){ $scope.state = ''ngRepeatFinished''; }); }) .directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', scope: { columnselector: ''@'', first: ''=?'', middle: ''=?'', last: ''=?'', index: ''=?'', odd: ''=?'', even: ''=?'', }, link: function (scope, element, attr) { if(scope.last){ scope.$emit(''ngRepeatFinished''); } } }; });

td { display: block; }

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app" ng-controller="ctrl"> <h4>{{state}}</h4> <table> <tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch" index="$index" odd="$odd" even="$even" first="$first" middle="$middle" last="$last"> <td>{{trData}}</td> </tr> </table> </div>

Pero te recomiendo encarecidamente que rediseñes la lógica

Según tengo entendido, quieres mostrar span-tooltips solo para td que de forma más amplia, definitivamente debes usar otra directiva, y en segundo lugar, requerir primera directiva, para que puedas usar su lógica de controlador, o lo que sea. De todos modos, un mejor diseño te ayudaría, así que mejor pienses en algo más profundo


Si desea utilizar el alcance del controlador con una directiva, debe hacer lo siguiente

app.directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', link: function (scope, element, attr) { var columnselector = attr.columnselector; console.log(scope[columnselector]); } }});

Esto no creará ningún ámbito para la directiva, y aún puede acceder al valor de columnselector. Si desea pasar la función en el selector de columnas, puede hacer $ parse (attr.columnselector). Si es un valor, entonces $ parse no es necesario.


Cuando define el alcance en la directiva está creando un alcance aislado. La forma más fácil de pasar en la $ última variable sería como otro atributo:

<tr fixed-column-tooltip columnselector=".td-keyField" ng-repeat="trData in trDataWatch" last="$last">

Su alcance de directiva se vería así:

scope: { columnselector: ''@'', $last: ''=last'' }

O simplemente puede acceder al alcance principal dentro de su función de enlace:

link: function (scope, element, attr) { if (scope.$parent.$last === true) { // Will evaluate true one time } }

En ese caso, no necesitará otro atributo ni necesitará definir $ last en su alcance de directiva. JSFiddle


Podrías usar,

''use strict''; angular.module(''cmt.cases.directives'') .directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', scope: { columnselector: ''@'', $last: ''=$last'', }, link: function (scope, element, attr) { if (scope.$last === true) { ....

el segundo parámetro para el alcance pasará $ último parámetro por referencia.

EDITAR:

Como el $ last solo está disponible en el alcance del elemento repeat, puede obtenerlo del ámbito del elemento, como este

''use strict''; angular.module(''cmt.cases.directives'') .directive(''fixedColumnTooltip'', function ($timeout) { return { srestrict: ''A'', scope: { columnselector: ''@'', }, link: function (scope, element, attrs) { var elemScope = element.scope(); if (elemScope.$last){ ...... } } }


Simplemente. Usa tu argumento de atributo en tu función de enlace ...

link: function(scope, element, attributes, ctrl) { var selector = attributes.columnselector; }

No sé por qué leo respuestas extensas, chicos en serio.


A pesar de ser casi completamente nuevo en Angular, estoy respondiendo mi propia pregunta, pero aún quiero respuestas adicionales en caso de que la forma en que resolví mi problema no se considere "idiomática" angular.

Específicamente, en lugar de usar un ámbito aislado, aproveché el tercer attrs atributo / atributos attrs (atributos) en mi código a continuación, para obtener el nuevo atributo columnselector en el html junto con mi directiva. ¿Es esta una práctica generalmente aceptada?

''use strict''; angular.module(''cmt.cases.directives'') .directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', link: function (scope, element, attrs) { if (scope.$last === true) { $timeout(function () { element.parent().find(attrs.columnselector).each(function() { var td = $(this); var span = td.find(''span''); if (span.width() > td.width()){ span.attr(''data-toggle'',''tooltip''); span.attr(''data-placement'',''right''); span.attr(''title'', span.html()); } }); }); } } } });

ADENDO: Como puede ver en los comentarios, no he podido obtener el código de esta respuesta , a pesar de intentarlo de diferentes maneras. Si estoy haciendo algo mal con respecto a la incorporación de esa respuesta, por favor hágamelo saber.

Mientras tanto, he encontrado otra manera de hacerlo, pero es casi seguro que se trata más de un "olor a código" que de aprovechar el argumento attrs . Específicamente, descubrí que puedo usar un alcance aislado y luego acceder al atributo de alcance $parent alcance. Luego comenzaría mi código de la siguiente manera, pero no estoy abogando por esto, sino que lo estoy notando, ya que parece que TMTOWTDI (hay más de una forma de hacerlo) ciertamente se aplica a Angular:

''use strict''; angular.module(''cmt.cases.directives'') .directive(''fixedColumnTooltip'', function ($timeout) { return { restrict: ''A'', scope: { columnselector: ''@'' }, link: function (scope, element, attrs) { if (scope.$parent.$last === true) { $timeout(function () { element.parent().find(scope.columnselector).each(function() { ...