Angular conditionally use directive attr inside directive template - javascript

I have a problem with using directive conditionally inside another directive,
so let's say I have one directive 'myGrid' and in it's template I have something like this:
<table my-grid-resizable>...</table>
and I want to use myGridResizable directive only if I use myGrid directive like this:
<my-grid resizable="true" />
But I don't want to use ng-if inside template of myGrid directive.
I tried this:
if (scope.resizable) {
angular.element(element).find('table').attr('my-grid-resizable', ''); }
But it's not working, attribute is added but directive is not working, recompiling directive is't helping as well.
Thanks for help in solving this

You're just setting the attribute, however, this does not mean that the DOM will be digested on it's own. The reason your DOM doesn't update is because you're not updating any model or binding. You're just modifying the DOM.
So you're gonna have to manually compile your element like,
First, inject $compile in your directive or controller (whichever is applicable)
Then do:
if (scope.resizable) {
angular.element(element).find('table').attr('draco-grid-dynamic-table', '');
var html = angular.element(element).find('table').html();
var compiledHtml = $compile(html)(scope);
angular.element(element).find('table').html(compiledHtml);
}
This way, however works, but is not an angular way and is highly discouraged.
I do not understand why you don't want to use ng-if structure. It is the angular way of doing things.

Related

Angularjs - is there a way to programatically click on an HTML <select> element?

I've seen a javascript solution that goes a little something like this:
var select = document.getElementById('selectId')
select.click();
Is there an AngularJS approach/best practice to the same thing? (Off the top of my head, you'd wrap the above code in an ng-click)
Yes there is. Here's the angular equivalent of what you have in JavaScript
angular.element('#selectId').trigger('click');
Working example
Any DOM manipulation in angular should occur inside of a directive.
View
<div id="selectId" clickMe>content</div>
Inside of a directive the link function triggers after the view is compiled. The second parameter in the link function is the element which the directive is placed on, this gives performance benefits since there is no need to traverse the dom. It is a JQlite element which you can directly call methods on.
Directive
app.directive('click-me', function(){
return{
link(scope, el, attr){
$(el).trigger('click');
}
}
});

trying to add click inside a re-usable directive to a element that may have different classes be different element and may have different text

so here is the desire: I need to add a directive to any html element and pass it an id. This id is then used to populate a method that submits a form that has that id on the page.
Some devs have used a button some have used an anchor tag so I do not want the type of element to be part of the method. It is intended to be highly re-usable.
I already have it working like this:
angular.module("App").directive("submitform", submitFormDirective);
function submitFormDirective(){
return {
restrict: 'A',
scope: true,
link: function($scope, $element, $attrs){
var selector = $attrs.submitform;
$element.on('click', function(){
angular.element(selector).submit();
});
}
}
}
But this uses jquery for the "on" method. I want a fully angular method. Or one that does not "fight" with the framework or use jquery.
The way I am doing it now I only need to apply this attribute to the element. submit-form="#id-of-form" And I would like to keep that functionality becasue it is clean and concise. So I need to be able to add the ng-click to the element dynamically without using the limited template function which would limit the element being effected, inside the submitFormDirective.
The problem is that the $attrs.$set('ngClick', 'submitForm()') runs after the digest and $compile does not seem to work for me. I need to be able to add the click and run the compile on only this element or use a different phase that will happen before the app compile will run. But I have tried using compile to att the attr in conjunction with link adding the method to the scope to no avail. Seems strange that you would not be able to add a event from a directive. I must be missing something. Can someone help?

AngularJS use directive-name in scope as string

I have nested angular.js templates. Each template has it's own directive. Based of the data passed to the ParentTemplate, angular.js should call the matching directive.
<div class="parent-template">
<div class="{{childTemplate}}"></div>
<div class="template1"></div>
</div>
Lets say that $scope.childTemplate = template1. Both divs evaluate to the same content <div class="template1"></div> but only the second div calls the directive to show the template as expected.
I need a dynamic way to call the corresponding template directive
Here is the directive for template1
angular.module('myApp').directive('template1', function(){
return {
restrict: 'C',
templateUrl: 'templates/template1.html'
}
});
Directives for other templates directives work similar.
You try to set the class of the DOM element.
You can do this with ngClass.
Otherwise if you would like to set your directive as an attribute of the DOM element. Like this: <div template1> </div>
You can try this way:
var myEl = angular.element( document.querySelector( '#divID' ) );
myEl.attr('myattr',"attr val");
Try:
<div ng-class="childTemplate"><div>
Did you ever solve this? I have a similar challenge, which I currently solve by using ng-include, like so:
<div class="parent-template">
<div ng-include="'templates/template1'"></div>
<div class="template1"></div>
</div>
This works for your example, but gets more tricky when a directive does more than just wrapping a template, e.g. working with the DOM or adding a controller.
What you can do in that case is using the directive inside the template.
However, this feels all kinda hacky, i'd like a more direct approach
This was, for me, all sparked by an article on react plugins, in which you basically enumerate over a set of react component to get a feature set: https://nylas.com/blog/react-plugins

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