Writing directives in the link function of a directive in angular-js - javascript

I have defined a directive in angular.js. That directive has a link function and a controller function, and no template, so all the view is generated in the link function. In the link function I am doing the following:
var button=angular.element("<a>");
button.addClass("ng-click: previousLink();");
//previousLink() is a function defined in the scope.
//I am doing it like that, because before that one I attempted to do:
//button.prop("ng-click", "previousLink()");
//button.text("Previous");
//but for some reason it was showing on html as <a>Next</a>, without adding the property.
It does not work. If I click the button it does nothing. If, instead of doing this in the link function in code I were doing it using a template, it would work. For some reason I need to make some manipulations using jquery in the link function. What should I do? Is there anyway to make this work, or would I have to use both template and link function and combine things there?

To use $compile you need to follow your existing code with something like:
$compile(button.contents())(scope);
If you want it to be dynamic, you can put this inside a $watch like so:
link: function (scope, ele, attrs) {
scope.$watch(attrs.yourval, function(html) {
var button=angular.element("<a>");
button.addClass("ng-click: previousLink();");
$compile(button.contents())(scope);
});
}
$compile attaches the scope (supplied as a parameter) to the html you have defined. This will make your button clicks work properly.

Related

angularjs variable in javascript

This is the first time to use angular js.
The following code gives desired output:
Hello
It opens a page:
http://www.example.com/xyz/cat/
But the below code is not working as expected:
<a href='javascript:void(0)' onClick='javascript:window.open("http://www.example.com/xyz/{{life.animal}}/","Windows","width=1150,height=450,toolbar=no,menubar=no,scrollbars=yes,resizable=yes,titlebar=no,location=no,directories=no,status=no");return false')'>Hello </a>
It opens page:
http://www.example.com/xyz/{{life.animal}}/
I think I am doing some basic mistake but please help me.
The Angular scope is not available outside of Angular, i.e. vanilla JS.
To set a click function the angular way you should use ng-click
Create a function in your controller or directive such as
scope.open = function() {
$window.open(...)
}
In the template do
ng-click="open()"
angular doesn't interact with strings, but you try to do that in your onclick handler that opens a window (you pass a string there). Stop the string and concat with the variable:
onClick='javascript:window.open("http://www.example.com/xyz/" + life.animal)'
Also, as #Enzey has noted, use ng-click instead of onClick, and then bring out the javascript from your html and do that stuff in a controller instead.
E.g.:
HTML
Foo
Controller
$scope.myFunction = function() {
window.open(...whatever...);
}
The double hash are used for angular directives not for Javascript Vanilla apart of that is better if you use ng-href instead href in a <a> tag. You can check this here

Call a function within a TypeScript Angular directive?

For a while now, I've been following an Angular directive TypeScript pattern that I really like. I give the directive its own isolated scope by creating a new controller.
I've run into a situation where I need to call a function within my Angular directive from outside of the directive.
For example, I have a really simple function that opens a popup within my directive. The directive's controller has something like:
public openPopup() {
this.uiClasses.popup = "open";
}
The corresponding view has a few notable elements like:
<div ng-click="vm.openPopup()">Open the pop up</div>
<div ng-class="vm.uiClasses.popup">the actual popup</div>
With some really basic CSS, this works like a charm. But, what if I have a controller that creates this directive, and wants to trigger the directive's openPopup function. I want to do something like this:
class PageController {
private scope: any = null;
static $inject = ["$scope"];
constructor($scope: any) {
$scope.vm = this;
}
public openTheDirectivePopup() {
// from here, how can I call the openPopup on a specific directive?
}
}
The corresponding view:
<div ng-click="vm.openTheDirectivePopup()">I can open the popup inside the custom directive</div>
<my-custom-directive></my-custom-directive>
I also want to be able to have multiple instances of these directives on the same page without conflict.
It seems like this should be do-able, but I can't quite wrap my head around it. Any suggestions?
What I would do in that case is add a "isOpen" attribute to your directive, and toggle that value true / false from your ng-click call.
It would look like this in your HTML:
<div ng-click="vm.isOpen = true">I can open the popup inside the custom directive</div>
<my-custom-directive isOpen="vm.isOpen"></my-custom-directive>

How to pass value back from angularjs directive scope with javascript event

What Im trying to accomplish: I have jQuery plugin that I want to wrap to be an angular directive. And to do this i need to pass params to it, and the plugin have it ownonchange` even where I'm trying to change passed values so it will be reflected in the original scope. And I get some really unexpected and strange results.
Here is fiddle number one:
http://jsfiddle.net/q1915b38/2/
Here I tried to simulate minimal example of what i want to accomplish. But as you see it just does not work at all. Value in the original controller scope doesn't change. But in real world example it act a bit differently.
And here goes fiddle number 2.
http://jsfiddle.net/ne5hbgxp/
The only thing i changed from first one is template from template:
template: "<input type='text' id='blah' />",
to
template: "<input type='text' id='blah' ng-model='abc' />",
Basically i added to template an ng-model attribute which I don't use anywhere at all. But it just goes from totally not working to working with glitches. Now when change trigger first time nothing happens. But when it triggers second time - value from previous change got passed into original scope. When I change 3 time value - the value from second time goes to controller. And so on. So basically it have a delay with one step back for unknown for me reason. And this is exact behavior that I face in my real world example, although there no ng-model at all and all content generate via jQuery plugin.
So basically my questions are following:
1) Why its not working in first example
2) Why its working in second example with this strange behavior with one step delay? What the logic on this behavior?
3) What is a correct way to solve this ?
Since you're using jQuery to update something in your directive, a call to $apply() is needed to trigger an angular digest cycle
link: function(scope, iElement, iAttrs, controller) {
$('#blah').change(function() {
scope.value = $(this).val();
scope.$apply();
});
}
JSFiddle Link
However looking at this a bit closer, is there a reason why you prefer jQuery .change() in this example? Angular offers ngChange, which may be just what you are looking for, since you will be alleviated from explicitly calling a digest cycle since we're in Angular world and not battling jQuery so to speak. An example may include...
<input type='text' id='blah' ng-model='abc' ng-change='update()'/>
scope.update = function() {
scope.value = scope.abc;
}
JSFiddle Link with ng-change
Issue is pretty simple... events that change scope that are outside of angular's core directives aren't visible to angular so you you need to notify angular to perform a digest so the view can be updated.
This is done with $apply() or can use $timeout() to prevent calling $apply() while another digest cycle is in progress
link: function (scope, iElement, iAttrs, controller) {
$('#blah').change(function () {
var $el =$(this);
scope.$apply(function () {
scope.value = $el.val();
})
});
}
I would suggest taking advantage of the iElement being exposed in the directive. This is a jQuery object when jQuery is included in page prior to angular

Adding controller to dynamically constructed div in AngularJS

I am attempting to add a controller to a dynamically constructed div in angular. However, the controller doesn't seem to be loading and I cannot add corresponding events to the click function.
In the example below, I am constructing this div within a separate parent controller termed 'employeeTableCtrl'. Within the parent controller, when a user clicks the 'more info' button, the new divs are constructed. In the container of this child is where I am looking to attach a new controller.
$scope.moreInfo = function(employee) {
$("<div class='employeeWindow' ng-controller='employeeWindowCtrl'> " +
"<button class='closeButton' ng-click='close()'> x </button> </div>".appendTo("#employees");
}
And in the separate controller I have:
.controller('employeeWindowCtrl', [
'$scope', function ($scope) {
$scope.close = function() {
alert('clicked the x');
}
}
])
The divs are all being constructed correctly, but the the 'employeeWindowCtrl' is not being attached such that my 'click()' function is not being executed.
Does anyone have any tips? Maybe I am approaching this all wrong?
Thanks
What you're looking for is a directive - a chunk of html that has a sort of private controller via the link function. Create the directive in a separate template, place your controller functionality (if it indeed is appropriate for a controller) in the directive's link function and use ng-show to reveal on click. If we had more code to play with I could give a better example of all of this.
https://docs.angularjs.org/guide/directive

AngularJS to render a template inside a compile inside a loop inside a partial

I have a partial, which has a directive which renders a bunch of things in a loop, using compiled HMTL-as-a-string inside the directive. This HTML-as-a-string itself contains an ng-include, which doesn't render out.
Please see my jsfiddle example
Basically, this doesn't include template2.html:
element.html('<span>The name is ' + scope.content.name + '!</span><div ng-include src="template2.html"></div><br>');
Any pointers would be much appreciated.
Thanks!
WORKING DEMO
just needed to write as
src=" \'template2.html\'"
var linker = function(scope, element, attrs) {
element.html('<span>The name is ' + scope.content.name + '!</span><div ng-include src=" \'template2.html\'"></div><br>');
$compile(element.contents())(scope);
};
more info in DOCS
Vinod's answer above (replace src="template2.html" with src="\'template2.html\'") is correct, though I would recommend using an actual template instead of manually compiling the template yourself inside the link function. In your example, you aren't actually receiving the benefit of the two way binding. You are just taking the html output of the compile function, and it will never update if the underlying data changes. Here is your example modified to show the bindings (and Vinod's template fix):
http://jsfiddle.net/kf3vZ/5/
Notice how if you change the value of any of the checkboxes, the value in the directives do not change.
Now here is a version using the template argument to the directive:
http://jsfiddle.net/kf3vZ/7/
Now if you change the text fields, the directive values will change also.
Another note, since you are already using the script tags for your templates, you could replace template in your directive with templateUrl and provide the id of the script template.

Categories