I have an Ionic application with an SVG object with many rectangles (e.g. <rect class="info" id="1001" width="20" height="20" transform="translate(40,40)" />). I would like to add an ng-click directive to each of these without going through and manually appending ng-click to each of them.
Currently, instead, I have the following code in the controller:
$(document).ready(function() {
$('#svg').on('click', 'rect.info', dispInfo);
}
This works as needed, but does not seem to be the "Angular" way. Is there a better way of doing this?
I have tried the following which seemed more angular, yet to no avail:
var elems = $('#svg rect.info');
elems.attr('ng-click', 'dispInfo()');
$compile(elems);
This successfully adds the ng-click directive to the proper elements, but they do not fire. Could it be a problem with the way I am calling $compile ?
To be in more angular way, why cant to wrap your svg rectangle with a directive and add ng-click as part of directive template?
The problem I see with your code is, $compile function accepts html template.
You can try the below,
var elems = $('#svg rect.info'),
$parent = elems.parent();
elems.attr('ng-click', 'dispInfo()');
elems = $compile(elems.html())($scope); // pass your scope variable instead of $scope
$parent.empty().append(elems);
Related
I am trying to call a function using ng-click when dynamical elements are created but with no success so far. Here is my code
$scope.myfunc = function(){
alert("anything")
}
var divtoappend=angular.element( document.querySelector('#slist'));
divtoappend.append("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>");
...
No error is thrown and nothing happens on click
You have to compile DOM with $compile API, before injecting into DOM tree, like below.
divtoappend.append($compile("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>")($scope));
By compiling DOM angular will put all HTML level bindings in $$watchers array of $scope to make sure UI is up to date on every digest cycle.
You need to compile the dynamically generated HTML so that it is under the scope of AngularJS.
Just compile inside append method like
divtoappend.append($compile("<button class = 'optv' ng-click='myfunc()'>" +mybutton+ "</button>")($scope));
Before this inject $compile in your controller.
I have created a plunkr see this plunkr link
You need to compile your DOM elements as follow using $compile
$compile(divtoappent)(scope);
I'm trying to set a directive to my inputs accordingly.
So let's say I have this input:
<input type="foo" id="myinput" maskvalue> </input>
This works fine on my app, the problem is when I try to insert "maskvalue" dynamically using the "setAttribute" it doesn't work, here's what I'm trying to do right now:
element = document.getElementById('myinput');
if(element){
element.setAttribute('maskvalue', "");
}
This code will successfully insert my directive to the dom element, but will take no effect. It seems that is impossible to insert a custom directive to the dom when it was already loaded, am I wrong?
But that's basically the question, how can I insert a directive dynamically to a dom element?
Thanks
Use Angular's $compile command to Angular-ize this. Basically, you need to notify Angular that you have made a change so it can do its magic.
function MyController($scope, $compile) {
element = document.getElementById('myinput');
if (element) {
element.setAttribute('maskvalue', "");
$compile(element)($scope);
}
}
Make sure you do this in an Angular controller that has $compile and $scope injected into it.
I'm trying to wrap the SharePoint People Picker in an AngularJS directive. In order to initialise a people picker I need to place a div on the page, give it an ID and pass that ID into a SharePoint function.
I have this working with a basic directive like this:
<sp-people-picker id="test"></sp-people-picker>
But I wish for the directive to be useable anywhere, including in a repeating section:
<div ng-repeat="item in dataset">
<sp-people-picker id="test-{{ $index }}"></sp-people-picker>
</div>
This fails. I stepped through the code to see what was going wrong and found that while I was happily calling the SharePoint people picker function with "test-0" it was failing to find the element. document.getElementById("test-0") returned null. The reason for this is that my div still had the id "test-{{ $index }}" and only gets "test-0" AFTER my directive has compiled.
How can I make sure my directive runs after the {{ }} has been rendered?
(Not tagging with SharePoint as the SharePoint stuff is just the context, it's not actually relevant to the issue I'm trying to solve)
You need to use attrs.$observe inside your directive link function, that will act as the same as like $watch, the difference is it can watch on the {{}} interpolation directive, Your link function will look like below. It call function whenever interpolation directive gets evaluated.
Directive(Link Function)
link: function(scope, element, attrs){
attrs.$observe(attrs.id, function(newVal, oldVal){
//here you can get new value & `{{}}` is evaluated.
});
}
I have a directive called "resizable" that adds functionality to an element to make it resizable.
I want to conditionally apply this directive to an element from a controller.
When I add this directive at run-time using attr, the attribute for the "resizable" directive is added, but the directive doesn't execute.
Here's an illustration: http://jsfiddle.net/HB7LU/3995/
What I'm expecting is that when $('span').attr('resizable', ''); is called, the class funky should be added to the span. Why doesn't it?
You need to use the $compile directive to notify angular of the changes. Basically the logic goes like this: "I've changed something within my element that you should be concerned about. Please compile the DOM against my scope":
function Controller($scope, $compile) {
// Apply resizable directive to span
var span = $('span');
span.attr('resizable', '');
$compile(span)($scope);
}
Documentation here
NOTE: You SHOULD NOT use jQuery natively within a controller (... or anywhere really). It may select span tags outside of your element of interest. You SHOULD try writing a directive to wrap the logic that applies your resizable directive.
I am developing a multi data app that is using angular.js and d3.js. I am having a hard time to include the <svg> into my scope.
What is happening now is that the directive ngTests is being loaded before the ngRepeat executes it's methods.
I am putting the fiddle here so you guys can have a better idea.
jsfiddle
<ng-chart></ng-chart>
PS: I can get the td id on my ngTests directive, but it doesn't update at all <td ng-tests id="histogram{{$index}}".
If I change this line to <td ng-tests id="histogram">, use histogram as ID on my directive and change my ngTests directive to read only "#histogram" it creates my svg 6 times on the first table of my ngRepeat, which is not the result I am expecting.
Thank you.
Do two things. In your ngChart directive you have the index attribute specified like index="index" but it needs to be index="{{$index}}". Then, to read the attribute value from the other directive, instead of accessing the attribute directly like attrs.index you should be using attrs.$observe more like the following:
attrs.$observe('index', function(observedIndex) {
console.log('observedIndex:', observedIndex);
});
This way when the index is changed (e.g. by another directive) you get notified and can update the element's text. I forked the fiddle and got it working here.