what directives creating all angularjs

angularjs - directives - what is a directive angular



Directiva AngularJS para desplazarse a un elemento determinado (7)

Tengo una variable de ámbito $ scope.first_unread_id que se define en mi controlador. En mi plantilla, tengo:

<div id="items" > <ul class="standard-list"> <li ng-repeat="item in items" scroll-to-id="first_unread_id"> <span class="content">{{ item.content }}</span> </li> </ul> </div>

y mi directiva se ve así:

angular.module(''ScrollToId'', []). directive(''scrollToId'', function () { return function (scope, element, attributes) { var id = scope.$parent[attributes["scrollToId"]]; if (id === scope.item.id) { setTimeout(function () { window.scrollTo(0, element[0].offsetTop - 100) }, 20); } } });

sin embargo, funciona dos preguntas:

  1. ¿Hay una mejor manera de obtener el "first_unread_id" fuera del ámbito del controlador en el ámbito directo que interroga. $ Parent? Esto parece un poco ''asqueroso''. Esperaba poder pasar eso a través de la vista al directo como un parámetro sin tener que repetir eso en cualquier elemento li.

  2. ¿Hay una mejor manera de evitar la necesidad de la llamada a setTimeout ()? Sin él, funciona a veces , imagino debido a la diferencia en el tiempo de diseño. Entiendo que la sintaxis que he utilizado es definir una función de enlace, pero no me queda claro si se trata de un enlace previo o posterior por defecto, y si eso es importante para mi problema.


  1. No debería necesitar el alcance. $ Parent - ya que heredará el valor del alcance primario, y cuando cambie en el alcance principal se pasará.
  2. El valor predeterminado es una función de enlace posterior. ¿Tiene algunas imágenes o algo de carga que haría que el diseño de la página cambie poco después de la carga inicial? ¿Has probado un setTimeout sin tiempo, por ejemplo, setTimeout (function () {})? Esto aseguraría que esto iría ''uno después'' de que se haga todo lo demás.
  3. También cambiaría un poco la lógica de su directiva para hacerlo más general. Me gustaría desplazarme al elemento si una condición dada es verdadera.

Aquí están esos 3 cambios:

html:

<div id="items" > <ul class="standard-list"> <li ng-repeat="item in items" scroll-if="item.id == first_unread_id"> <span class="content">{{ item.content }}</span> </li> </ul> </div>

JS:

app.directive(''scrollIf'', function () { return function (scope, element, attributes) { setTimeout(function () { if (scope.$eval(attributes.scrollIf)) { window.scrollTo(0, element[0].offsetTop - 100) } }); } });


En combinación con $uiViewScroll UI Router, terminé con la siguiente directiva:

app.directive(''scrollIf'', function ($uiViewScroll) { return function (scope, element, attrs) { scope.$watch(attrs.scrollIf, function(value) { if (value) { $uiViewScroll(element); } }); } });


En combinación con @uri, esto funciona para mi contenido dinámico con ui-router y stateChangeSuccess en .run:

$rootScope.$on(''$stateChangeSuccess'',function(newRoute, oldRoute){ setTimeout(function () { var postScroll = $state.params.postTitle; var element = $(''#''+postScroll); var pos = $(element).position().top - 100 + $(element).parent().scrollTop(); $(''body'').animate({ scrollTop : pos }, 1000); }, 1000); });


Igual que la respuesta aceptada, pero usa el método incorporado de javascript " scrollIntoView ":

angular.module(''main'').directive(''scrollIf'', function() { return function(scope, element, attrs) { scope.$watch(attrs.scrollIf, function(value) { if (value) { element[0].scrollIntoView({block: "end", behavior: "smooth"}); } }); } });


Para obtener una respuesta que tome la mejor de las respuestas aquí, en ES6:

Archivo: scroll.directive.js

export default function ScrollDirective() { return { restrict: ''A'', scope: { uiScroll: ''='' }, link: link }; function link($scope, $element) { setTimeout(() => { if ($scope.uiScroll) { $element[0].scrollIntoView({block: "end", behavior: "smooth"}); } }); } }

Archivo scroll.module.js

import ScrollDirective from ''./scroll.directive''; export default angular.module(''app.components.scroll'', []) .directive(''uiScroll'', ScrollDirective);

Después de importarlo en su proyecto, puede usarlo en su html:

<div id="items" > <ul class="standard-list"> <li ng-repeat="item in items" ui-scroll="true"> <span class="content">{{ item.content }}</span> </li> </ul> </div>


Suponiendo que el elemento padre es aquel en el que nos desplazamos, esto funciona para mí:

app.directive(''scrollIf'', function () { return function(scope, element, attrs) { scope.$watch(attrs.scrollIf, function(value) { if (value) { // Scroll to ad. var pos = $(element).position().top + $(element).parent().scrollTop(); $(element).parent().animate({ scrollTop : pos }, 1000); } }); } });


Terminé con el siguiente código (que no depende de jQ) que también funciona si el elemento desplazable no es la ventana.

app.directive(''scrollIf'', function () { var getScrollingParent = function(element) { element = element.parentElement; while (element) { if (element.scrollHeight !== element.clientHeight) { return element; } element = element.parentElement; } return null; }; return function (scope, element, attrs) { scope.$watch(attrs.scrollIf, function(value) { if (value) { var sp = getScrollingParent(element[0]); var topMargin = parseInt(attrs.scrollMarginTop) || 0; var bottomMargin = parseInt(attrs.scrollMarginBottom) || 0; var elemOffset = element[0].offsetTop; var elemHeight = element[0].clientHeight; if (elemOffset - topMargin < sp.scrollTop) { sp.scrollTop = elemOffset - topMargin; } else if (elemOffset + elemHeight + bottomMargin > sp.scrollTop + sp.clientHeight) { sp.scrollTop = elemOffset + elemHeight + bottomMargin - sp.clientHeight; } } }); } });