Event for any change in scope variable - angularjs

I wanted to have a Dialog box for asking to save the current changes or not. For that I was searching for an event in AngularJS which triggers on change of any scope variable.
As per my logic I will achieve this by creating event on every control and update a variable to say 'Modified' else will have default value.
Is there any other way? Since my logic will need an event on every control.

If you're using a form directive, this is pretty simple. The value of myForm.$dirty will be true if any property has changed. You can even check an individual field with myForm.myField.$dirty.
If you're not using a form, you should probably consider it for what it sounds like you're trying to accomplish. One of my favorite angular features as it makes validation, etc. a breeze!
Reference: angular docs

Take a look at $scope.$watch(...) on the Angular docs, there is a great discussion on how $watch works here on another Stack Overflow question
You should, at the very least, be able to trigger alerts when specific scope-elements have changed. If you are using a form, then the $dirty approach above is absolutely a brilliant way to go.

Related

Is it possible to perform a two way binding on a custom directive with ngModel?

My use case is completely different. When I strip off all the other factors, it boils down to this.
Say I have the following input element
<input type="text" [customDirective] [(ngModel)]="myValue" >
The job of this customDirective is to look into value entered by the user and changed its value based on the input on the fly.
How to achieve two-way binding for this.
I played around with ControlValueAccessor, DefaultValueAccessor. But no matter what I do, I was not able to achieve the two-way binding. The maximum I achieved at one time is view update on model update but not the other way round. But that code is somewhere lost.
Here is the vanilla plunker link.
PS: I already referred the following. But none of them were helpful in achieving 2-way binding w.r.t to directive
http://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html
angular2 wysiwyg tinymce implementation and 2-way-binding
Thanks in advance
Finally figured out how to do this.
Model to UI changes can be done using ControlValueAcessor
UI to Model can be done like below
import {Output} from '#angular/core';
Use the event emitter
#Output() ngModelChange = new EventEmitter();
Whenever data gets changed emit the event
this.ngModelChange.emit(YOUR_NEW_VALUE);
Here is the detailed example
Using Tinymce editor as a directive

Changing value of input's model programmatically using angular

I'm using Ionic framework to create my app.
I have a text input, with ng-model="answer", and bellow a have a button that starts speech recognition and then replaces the input text with the spoken one.
The problem is that I can't change the input's text programmatically when using the mic with $scope.answer="any text", it looks like it just doesn't change the view's value.
I found that I have to use a directive in order to bind the model, but to be honest I don't know how to address it right now.
Also I've tried $scope.$apply() but it works only the first time and when I haven't wrote any test directly to the input yet.
What you are looking for may be Angulars $watch() function, so you can handle any model changes even outside of the input field.
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

Directive that binds to form input blur event

I would like to have a directive for my validation messages that takes the name of the form input being validated and then displays itself if the named form input is invalid. For the sake of good UI, I want this to only happen after the input is blurred. Here's a Plunkr: http://plnkr.co/edit/qLSsCHpAPLdZsCPG8iaf
Obviously, ctrl[attr.tgValidates] isn't giving me an object I can bind to (although it is referencing the correct field), but I'm not sure how to properly select the element I do want. jqLite doesn't have great support for selectors, so it's a tricky to do what I want without pulling in all of jQuery. I guess I could also pull in $document and select off that, but I'm wondering if there's a better, more Angular way to approach this?

angular - reusable dialogs

I need to build a dialog to be used with any item on a list of items. The dialog is pretty much the same regardless of the item except for the values of the fields which are obviously item dependent.
The directive I am building is reading the template from a file, compiles it with $compile and then binds (links) it to the scope of the item. The result of the binding is a DOM tree. To make the dialog visible I need to append this tree to some element in the existing DOM. The nature of my dialog is such that it makes sense to append it directly to the body tag. The dialog will be used many times in combination with different items on the list
So here is my question: How much of this process (compile, bind, append) can be done in advance? I certainly can run compile once. I can also bind the compilation result to the $rootscope and append (hidden) it to the body tag. This way I can later just turn on visibility and show the dialog.
But if it is already bound and attached to DOM, is it kosher to re-bind it to some other scope, if so - what's the right way to do it? Another question is is it even worth it? might be just re-insert it every time it is needed?
If you're only ever going to display one dialog like that at a time and you will use it frequently, you don't have to re-bind it to another scope, just change the data on the scope. Something like this:
Create a service for your dialog
Create the directive and inject your service into it. When the linking function executes, pass something like $scope.dialogData to the service so that the service can update the data.
Create a controller that gets the service injected. Set the dialog data through the service to display the dialog. Since you're modifying data in your controller that's on the directives scope, Angular notices that and updates your dialog.
Add ng-show on your dialogs wrapper to make it simple to implement open()/close() methods on your service.
Now you have a dialog that can be used from anywhere in your system, and you're just re-using the same directive without having to mess with the DOM or compilation.
This is indeed excellent question and I'm happy to see that more and more people are starting to approach dialogs as services.
Regarding your particular questions, here are some of my thoughts:
You can "cache" linking function (that is - function that is returned from the $compile call) and then call this function as needed (passing in scope variables).
Instead of inserting (hidden) compiled element you could only attach it on demand, when a dialog gets opened. On top of this I would rather attach modal element to the $rootElement instead of <body> just not to touch DOM elements above where ng-app was defined. Just not to touch parts of the DOM that AngularJS is not controlling.
IMO dialogs are really close to AngularJS routes (as they provide different "views") and as such it would be very nice to have ability to resolve promises before modal is shown (as with routes).
In fact there are number of things to consider when designing a good, generic dialog service and I hope that those advice, alongside with excellent input provided by others, will get you started. But this all is a bit theoretical so if you are looking at the implementation of what was discussed here you can have a look at this implementation. ($dialog service from http://angular-ui.github.com/bootstrap/ - it is fully customizable so can be used with CSS other than Bootstrap's. Documentation here).
It can be seen in action in this plunk: http://plnkr.co/edit/PG0iHG?p=preview
Excellent question I think. You're wondering if one can "hot swap" the scope of an element. I don't know if there's a way to do that, or even if there is, if that's the Angular way. I take it you looked at how ng-view works to get as far as you've gotten?
My advice is to do the $compile once, keep the result, the link or transclusion function or whatever it's called in Angular parlance, around somewhere. And call it for each needed instance of the dialog.

Performance issue when I have to set attribute of a model in multiple places (model bind to a change event)

I am binding my modal to the change event
#model.bind('change', #someAction)
Will performance of my app be affected if I am required to set/change attribute of my model and multiple places i.e. #model.set({someAttr:'attributeA'})?
Does doing a {silent: true}, #model.set({someAttr:'attributeA'}, {silent: true}) solve the problem of performance of the app?
The answer is "it depends". It's up to you to figure out what changes to your model deserve change events and which do not. There is no magical answer in this case to improve performance.
Passing {silent:true} is one way to prevent the change event from firing. Another optimization is to listen to changes to specific attributes within your model.
#model.bind('change:myAttr', #someAction)
This way, your action is triggered only if a specific attribute is changed and does not trigger if any other attributes are changed.

Resources