angular monitor DOM change outside angular's realm - javascript

Here is the jsbin link,
I want to use regular DOM API manipulation and feed it back to angular.
The result is if using $timeout, it works. but not window.setTimeout. I know it is not the right way to deal with angular. but in 3rd party component case, it makes sense to allow the 3rd party non angular developer to use pure vanilla or jquery to change the angular generated DOM attribute to get expected result.
How could we watch or observe the attribute change and update angular scope?
I found a hacky way to make it work by adding this line. $interval(function(){$(el).attr('info');},2000), you could comment it out in jsbin to see the expected behavior.
But it's not quite what i want. any better solutions?

Basically, Angular doesn't know that there is a change if you are outside the Angular context, so you need to tell Angular that something has changed.
One of the thing, you are already using is the $timeout service. But there is an another a cleaner solution for this.
The place where you are using jQuery to change the DOM, you can call tell angular to fix things:
angular.element(document.querySelector("body")).scope().$apply();
$apply() method call be trigger digest cycle manually which Angular does on it's own when you work inside Angular context.

Related

Angular 6 custom element interaction with parent DOM

I am using angular element for javascript error reporting.
I am following this tutorial for error handling and reporting in the angular application. This code is working in angular application but I want to reuse it outside the angular application. So I have packed this code in an angular element and used as a custom element in a non-angular application. But it doesn't work.
I think angular elements don't have the access to the scope of the page.
But I am not sure what is the problem here, I just want to know this is possible or not, If yes what mistake I am doing.
Thanks.
To access angular elements or component, you can go through this.
https://angular.io/guide/component-interaction
It allow you to access and manupulate element of another component.
If you are trying to access method from outside the source. you should go through ngZone
https://angular.io/api/core/NgZone

Where to wrap third party plugins in AngularJS?

I am new to Angular and I understand one of its 'rules' is that no DOM manipulation should exist in the controller. I have heard that a lot of people starting out with Angular dont completely understand this and end up writing JS code directly into their application, my understanding of this is if you are writing an Angular application you should completely forget about regular JavaScript.
I have found that in order to use a third party plugin or a regular JS script in an Angular app is to wrap it up in an object. I have read that usually this is done by either wrapping the script inside a directive or a service.
So I have a couple of questions:
What are the main concerns to think about when choosing between a directive or a service as a wrapper?
Are there major performance and/or maintenance issues between using a directive or service as a wrapper?
I suspect that if you are doing any http requests that you would in that circumstance use a service, that is the only thing that I know when you would use a service as a wrapper object
You should use directives. In their definition, they have a link attribute which receives a function. This function is executed after the directive template is rendered in the DOM. So inside this function you can access any element inside the directive template.
Remember: if you are going to do some DOM manipulation you should only execute it in the linker function of the directive that renders the DOM you're manipulating.
You can learn more about creating custom directives in https://docs.angularjs.org/guide/directive

Make angular reevaluate complete page

we recently switched to Angular 1.3.x and now noticed that it seems to perform much better dirty checking. However there is a case (changing the language for the complete site) where our old implementation expects a reevaluation of certain expressions. This doesn't work anymore. What we would need is to somehow reset angular's dirty checking to make it reevaluate all expressions at least once. Is there a way to do this?
$scope or $rootScope.apply() obviously does not work.
UPDATE for clarification:
We have created our own i18n filter, which uses a service to get appropriate translations. It can be used like:
{{'MyString'|i18n}}
If we change the language, it will cause the service to use different a translation package. However we change the language somewhere in our SPA and since the expression is just a string it will never change, thus it will not be evaluated, translated and re-rendered. Honestly, now that I think about it, I don't know how it ever worked with Angular 1.2.
BR,
Daniel

Can't get Angularjs to update view when model updates

I am an Angular newbie and I'm stuck. I have some code on jsbin.com --->(http://jsbin.com/ratageza/7/edit?html,js,output)
It's not pretty but it's showing essentially what I am doing.
In my real code I am using $http.get calls a RESTful backend to load data from a database, and $http.post calls to add to the database. All works fine as far as the database fetches and updates. But after I create a new object using the "Create" form, if I click "List All" my tournaments object is not updated.
I'm confused about whether I would need $apply after the $http.post call? I've tried using it but am either using it wrong or that's not my problem here. I've looked all around stackoverflow and can't seem to find the answer to my problem.
If anybody can see what I'm doing wrong I would really appreciate the help.
Thanks!
Check out the slight changes I made here: http://jsbin.com/ratageza/8/edit?html,js,output
The change is how you define your controller usage. You use TournamentController in two different places which actually gives you two instances of that controller with two separate, isolated scopes. Your List All view was bound to one instance while the Create view was bound to a completely different instance.
Also, your question about $apply. As a general rule, you should very seldom have to use $apply and you should NEVER use it in a controller as it's not safe to use there. Directives are really the only safe place to use $apply and even there it should only be used if data is being modified outside the scope of angular. The order in which things are processed, you find that if you use $scope.$apply() in a controller, you will frequently get exceptions about already being in a digest cycle.
http://jsbin.com/ratageza/10/edit this works.
It's not a $apply or $diget issue. Because you put TournamentController into to part of views. One is create and the other one is to show. That makes a different copy of $scope.tournament;
So I add a div to wrapper the Form and the table. Put the controller to it. Remove the form and table controller.
Hope this can solve your problem. :)

AngularJS and location.path()

I'm working on a webpage based on AngularJS and sometimes I need to change the path (the shebang if you prefer it). The thing is that sometimes $location.path("/my_path_here") works, but sometimes I need to call $scope.$apply() after calling $location.path to make the webbrowser switch to the new path.
Why is this happening?
EDIT:
Example http://pastebin.com/d1SjfCHd
Take a look at this question and Misko's answer: How does data binding work in AngularJS?
That answer explains the process in technical great detail. So, I'm gonna tell it in layman's terms.
AngularJS makes itself work by using dirty checking, there are sets of values that angular is watching. Everytime something big happens, (a click, a function call in controller), angular runs a digest cycle, comparing the watched values to see if there is any change. If there is a change, depending on the watcher, angular will take necessary action (update view, fire a callback, update route).
When you use default directives and no jquery event handling in controller, you will be fine.
However, if you do, you need to know that you are NOT in the angular's digest cycle. Which means the watchers will not fire until a digest occurs.
You need to know when are you updating a variable that is being watched. Mostly it is custom DOM event (or jquery events). When it is the case, you need to let angular know that something is changed and it needs to re-check what happened (ie. update watchers).
This is by doing scope.$apply() after you have changed something.
Bear in mind that you cannot run an $apply() if you are already in the angular's digest cycle. It will throw an error like $digest already in progress.

Categories

Resources