How to 'destroy' a directive in AngularJS? - javascript

I'm using a directive to separate the logic for an entity (for example, a person).
So I have a people service that stores an array of people like:
this.people = ["Person 1", "Person 2", "etc"];
The controller then injects that service, and sends data to a template that contains my directive. So my template looks something like:
<div ng-repeat="person in people">
<person name="person"></person>
</div>
Now, in my directive I have a delete function (called by clicking a button in the directive's template, which looks something like this (People service also injected into directive):
delete People.people[id];
The problem is, the rest of my directive's template remains intact. I want to remove the directive completely upon deletion. How is this possible? I've tried hiding it by using ng-hide and setting a 'deleted' property in the directive's scope to true upon deletion, but the empty (without data) directive template remains. I've looked into scope.$destroy(), element.remove(), etc, but nothing has worked and nothing seems really clear in the documentation...
How can I destroy/remove a directive completely from within itself (i.e. upon calling a delete function)?
Fiddle: http://jsfiddle.net/VSph2/107/
Click delete and the data is gone, but the directive (and template) remains, showing 'name:'. How can I remove the directive completely on delete?

You are deleting object, but empty element in array remains, it is just null reference instead of pointing to an existing object.
Use
this.peopleIds.splice(this.peopleIds.indexOf(personId), 1);
to remove it from array, and that element will not be rendered in for loop anymore.
Reference: How do I remove a particular element from an array in JavaScript?

Related

can element using ng-repeat access variable created by ng-repeat?

is this valid for ng-repeat in angularjs 1.7.x
<div
ng-repeat="item in items"
ng-class="item.id">
{{tab.label}}
</div>
I am confused with the usage of variable created by ng-repeat ie item in the element which it is attached to. I thought we can use it inside that element only.
I have checked that this works but wanted to understand if there is any example in documentation for this case.
As an extension to this , does ng-controller works the same way for keys attached to $scope.
Kindly give some reference as i have checked for ng-repeat that it works, i just want to understand why( or that it is the expected behavior)

Creating dialog with knockoutjs components

I already use custom binding with knockout for displaying jqueryui dialog, but I would like to use knockout component feature.
So, I would like to write something like:
<window params="isVisible: isVisible">
//there will be some html
</window>
And later somewhere in code:
self.isVisible(true); //That would open window
//or
self.isVisible(false); //That would close window
Problem is that I don't know how to apply $(element).dialog. When I register knockout component, I can only get container element of this component, but not injected element.
ko.components.register('window', {
viewModel: {
createViewModel: function(params, componentInfo) {
// - 'params' is an object whose key/value pairs are the parameters
// passed from the component binding or custom element
// - 'componentInfo.element' is the element the component is being
// injected into. When createViewModel is called, the template has
// already been injected into this element, but isn't yet bound.
// - 'componentInfo.templateNodes' is an array containing any DOM
// nodes that have been supplied to the component. See below.
// Return the desired view model instance, e.g.:
return new MyViewModel(params);
}
},
template: ...
});
So, componentInfo.element is parent node, and if I apply dialog with $(componentInfo.element) I will set as dialog parent node, then my window tag would be:
<div><!-- Dialog will be applyed there-->
<window params="isVisible: isVisible">
//there will be some html
</window>
</div>
I think it will work, but that extra div look unneeded here... Or this is the only way to do job done?
What is knockout.components way to do this? Thanks.
I had a similar requirement when I wanted to build a Knockout component for hosting a dialog window using Bootstrap v2 'modal' functionality. I used an observable boolean value in my page's viewModel, set to false initially. There isn't a simple way to communicate with components after they have been initialized, except by passing in observables via params.
This observable was passed as a param to a <dialog-window> component in the params, e.g.
<dialog-window params="visible: showDialog">[content]</dialog-window>
This then used a special binding handler for the 'modal' dialog, but in your case you could bind it direcly using a data-bind='visible: YourParam' attribute.
The main page could then simply call showDialog(true) to make the dialog visible.
Hope this helps.

AngularJS directives with children

I'm trying to make a directive that could be used like this:
<my-directive>
<name>Blah</name>
<age>20</age>
<address>
...
</address>
</my-directive>
My expectation was that I would be able to access the child elements in the link function and get their inner HTMLs. However, that does not work as you don't get the "previous" HTML. I followed the answer in this post and that gives me the previous HTML, but clone is "raw HTML". It's an array of HTML objects, and I can't really search it or anything.
Is there anyway to achieve what I'm trying to do?
Use in directive
transclude:true
And for
children drective
require: '^parent',
For example click here
Should be able to call children function on your element.
var children = element.children();

angular js input bind value

I have an input like this :
<input ng-model="mysearch.myfield" id="myid"/>
that is bound to a filter
<table><tr ng-repeat="row in list|filter:mysearch">...</tr></table>
If I modify the input value in the GUI, it works perfectly, but if I try to modify its value via javascript/jquery
$("#myid").val("newvalue")
The input value is updated but the mysearch.myfield is not modified
Actually, I have a list that appears on user actions (it does not exist on page load):
<li onclick="changeTheInputValue('newvalue1')">newvalue1</li>
<li onclick="changeTheInputValue('newvalue2')">newvalue2</li>
...
with
function changeTheInputValue(v) {
$("#myid").val(v);
}
And it does not work when I click on an "li" (the input value is updated, ut the mysearch.myfield is not modified)
I also tried
<li ng-click="mysearch.myfield = 'newvalue1'">newvalue1</li>
<li ng-click="mysearch.myfield = 'newvalue2'">newvalue2</li>
...
but it does not work :(
Any idea ?
Thanks,
any javascript executing outside the angulars event loop won't be efective in angular untill you apply it. in order to do that you need to get the relevant scope and $apply the changes, since is not clear, how and why you are modifying the value outside the angular scope there is nothing much i can say except you could do something like
function changeTheInputValue(v) {
$("#myid").val(v);
angular.element($("#myid")).scope().$apply();
}
that should let angular know about the changes, how ever this is a bad design if using angular. there are far better ways to accomplish this same thing w/o having mixed execution scopes. (angular/the rest);
You are modifying the value of the input "#myid" using direct DOM manipulation. AngularJS is not aware of this. If you want both the html and the value of mysearch.myfield to update correctly, you must do so by modifying the mysearch.myfield property directly, either in a controller or via an ng-model binding or something similar.
The main reason this isn't working for you has to do with how AngularJS modifies the DOM. When you use jQuery to modify the DOM, you are circumventing angular. Angular has no way of knowing if you have changed something in the DOM except if you do it directly through Angular itself. In particular, if you are curious, read about the $compile and $digest services.
Hope this helps shed some light on the subject!

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