AngularJS: when a user action affects both the model and the DOM

This is for an AngularJS application. I have a custom directive that depends on the service.

What I'm really interested in is the "angular way" to deal with user actions that affect both the model and the DOM. Code example:

HTML:

<form foo-places> <!--other stuff --> <span ng-repeat="place in places"> <button ng-click="removePlace(place)">remove {{place}}</button> </span> </form> 

JS:

 angular.module('foo.directives', []).directive('fooPlaces', function(placesService) { return { controller : function($scope) { $scope.places = placesService.places; $scope.removePlace = function(name) { placesService.removePlace(name); }; $scope.$on('placesChanged', function() { $scope.places = placesService.places; }); }, link : function($scope, element, attrs) { //code to do stuff when user removes a place } } }) 

When the user deletes the place (by clicking the button), I also need to do something that could be associated with the DOM, for example, scroll the window to the top, etc. It feels strange to have a function in the controller that concerns the model, and then another function in the directive that makes the DOM stuff ... but both are based on the same user action.

Did I change my mind or did I really miss something? How should I handle one user action that applies to both the model and the DOM?

+4
source share
1 answer

When you are dealing with AngularJS, you may have heard the phrase β€œModel is the only source of truth.” If you understand this part, then the rest of things will easily fall into place. This is the "Angular Way".

When a user interacts, he does not interact with the DOM or view. He interacts with the model. The view itself is simply a β€œview” of the model. There may be other views on the same model, so the model is the only source of truth. Now that angular allows you to make changes to the model when the user interacts. You make these changes, and as the model has changed, the view begins to reflect the changed state of the model.

Also, just to emphasize the separation of concerns, the directive should rarely address the service directly. A directive is part of the DOM, which means it is a fragment of a view. A service usually has something to do with business logic or is a model. In MVC or MVVM, you cannot directly interact with the model. You always use ViewModel or Controller between them. This minimizes dependencies.

Your ScrollToTop may be the service you call on your controller (see $ anchorScroll , which is a service in angular). It does not do what you want, but its a rolling service that you also need to implement.

EDIT:

To clarify, you do not do DOM manipulating things in services at all. A scenario in which you could look at the DOM manipulation material in a service is when what you are trying to do does not belong to any particular html element, but something that should happen at your application level.

Let me explain this. For example, if you are trying to do something like a dialog / modal window - in angularJS you would think that the directive is the ideal place for something like this, since it is a common user interface component. But if you think about it, the directive in AngularJS is related to the element. You always associate a directive with an html element. But, as we have seen, dialogue is not what you attach to an element, but rather something global in nature. This is probably the exception.

The same goes for some related things $window and $document (e.g. scrolling). They do not belong to any particular element (if you want to scroll inside the div, it must be a directive), therefore, they must be a service. It is also a service that you can probably introduce into the directive. Say, every time you run your directive, you want to scroll toTop or open a dialog. You can introduce these types of services in your directives. Services that you probably shouldn't introduce into the directive are services related to business logic. Consider the directive as a reusable user interface component.

Of course, you could create a higher level component (the material you are trying to) that creates the DSL, but then you need to know exactly what you are doing. Until then, I suggest that you stick to the simple old controller, directive, and services, and each of them manages its own problems.

+4
source

Source: https://habr.com/ru/post/1479650/


All Articles