ng-if not updating on scope destroy - javascript

I have an isolate scope directive. In this directive's link function I am compiling an html template and appending it to the document body.
const template = `<div ng-if="vm.open"></div>`;
body.append(template);
I have a button that toggles the vm.open flag on an ng-click. This works fine to show/hide my div. However, when I press the back button, my scope destroy event handler gets called and sets the vm.open to false. But in my DOM vm.open is still true.
Is this because ng-if made a new scope and since my directive is the 'parent' it doesn't destroy the ng-if's scope? I found another stackOverflow thread where using ng-show fixes this issue, which it does. But I would like to understand why it doesn't work with an ng-if.

try with
*ngIf={{vm.open}}

Related

Why does my ready function always run when controller or directive reinisilize

When my controller or directive reinisilize angular.element(document).ready(function(){...}); function always runs. Why?
I have two controllers and one directive. I change value from parent controller which assign to ng-repeat. Whenever I change this variable, controller reinsilize and ready function recall too.
See this link: angualr ready function
Your code is set up such that you are destroying and recreating things when you click the "change index" button:
that.changeIndex = function(){
that.arr = [{name : g++}];
that.isValid = !that.isValid;
}
ng-repeat destroys and recreates your myCon2 controllers when you create a new arr array:
<div ng-repeat="m in con.arr track by m.name" ng-controller="myCon2 as con1">
And ng-if destroys or recreates your my-dir directive when you change isValid:
<div my-dir ng-if="con.isValid">hey directive!!!!</div>
The controller and directive both attach a handler to document ready, which will run as long as the document is ready (not just as soon as it becomes ready). This makes sense because if your code loads after the document initially becomes ready, you'd usually still want it to run.
By the way, you shouldn't need to use document ready inside Angular controllers and directives. You can put your initialization code at the top of them, or you can use ng-init.

should I destroy directive scope or angular will do it

Could you please explain me one thing. Imagine we have directive called "myDirective". Here is html:
<div my-directive>
</div>
When we remove this div from DOM, will angular destroy scope of myDirective and its watchers or I have to listen the event "$destroy" on div DOM element and inside the listener to call scope.$destroy?
Usually when you remove a div from DOM, angularJS automatically deallocates events and destroys the scope, even if you don't listen to $destroy event.
So why you should use $destroy? You should use it to manually deallocate some non angularJS events and plugins (e.g. if you create a 'Kendo Grid' inside myDirective you need to destroy it inside the $destroy function using the plugin function to destroy it).
I suggest also to set all references to objects in the scope to null (best practice).

Updating Angular view model on button click

I'm trying to understand how Angular data binding works. I have created this sample that displays {{values.count}} inside a span element:
<body ng-app="testApp" ng-controller="testCtrl as values">
<span>Count = {{values.count}}</span>
<button id="incr">++</button>
</body>
<script>
testApp = angular.module("testApp", []);
testApp.controller("testCtrl", function () {
var values = this;
values.count = 5;
$("#incr").on('click', function () {
values.count += 1;
});
});
</script>
If I click on the button, values.count is incremented, but the span is not updated. I can get it to work if I place a ng-click="values.Increment()" on the button and create a values.Increment method in the controller, but what is the difference that makes one work and the other not?
You are doing it the wrong way. When using angular, you don't need to bind event handlers/access DOM elements for this purpose. Use built-in ng-click directive.
<button ng-click="values.incr()">++</button>
and
values.incr = function(){
values.count++;
}
You could even do it inline, <button ng-click="values.count = values.count+1">++</button>
The reason why your code did not update DOM is because of the way angular works. Even though you are incrementing the value inside the manually bound event handler angular is unaware of the update and it does not update DOM binding with the new value. Though a bad practice in your specific case you can achieve that by doing $scope.$apply() (but ofcourse you need to inject $scope in your controller) as well inside the event handler to manually invoke the digest cycle. General thumb rule when working with angular is the controller do not access DOM directly, Instead it just sets up data for the view and with the help of bindings and other built-in or custom directives you get the intended behavior in your application.
Read about scope life cycle and digest cycle

Where and how to modify transcluded content?

I want to buid a directive (let's call it "A") that accepts HTML for transcluded content and modify its transcluded content by adding ng-click handlers on it using a custom logic.
I thought that the pre-link would be a good place to do this, but apparently I was very wrong (it seems that the docs suggest against it).
Every "A" directive will accept its own (unique) content, so I cannot do this in the compile phase.
In the link function I am not sure what I can do...
So, has anyone done anything similar?
EDIT:
I forgot to mention this: The handlers for ngClick should be defined on the directive's scope, not the parent scope. I don't know if Angular allows this, but that's what I need.
In your template you should add ng-transclude on the element want to add your custom html to.
your use of the directive:
<attribute ng-click="clickMe()">
<div>
transcluded data
</div>
</attribute >
and in your template:
<span ng-transclude>
</span>
Hope it makes sense :)

Angularjs - ng-model undefined

I am building a rather complex directive in which I need access to ng-model on a specific element in the template which is enclosed into ng-if directive... I have a plunker and the explanation on how to see the issue is below.
In the .compile function of the directive I have a line of code that looks like this
ngModel = elm.find('textarea').controller('ngModel');
console.log(ngModel);
In my template, I have a something like this:
<div ng-if="views.view">
<textarea ng-model="exp.val"></textarea>
</div>
When I use ng-show my console.log gets an object of ng-model, no problem ...
The requirement is very strict however and I have to use ng-if. When I use ng-if my console log gets undefined
The actual working version of the problem exists in this plunker
If you change the line 6 in template.html into ng-if you can see the behavior.
How do I have to write this line to retrieve the model when inclosed in ng-if.
ngModel = elm.find('textarea').controller('ngModel');
I also tried using attach-if directive by Simon Sparks. This directive is pretty cool, it preserves the scope unlike ng-if so if you specifically need to not render HTML but you need to preserve scope it works great.
I still have the same problem with invoking ngModel as I am doing it but because of applying custom filters in the directive I have to update ng-model in this way.
I am this one step away from finishing this directive. Hoping someone can help.

Categories