using jqlite to target nested directive element - angularjs

I have a directive that has a template something like:
<div class="some-class">
<div class="some-inner-class">
<div class="class-to-target">
</div>
</div>
</div>
in the directives link function I would like to assign 'class-to-target' to a variable and then use addClass() and removeClass(). Can anyone recommend a clean way to achieve this?
Any thoughts greatly appreciated
C

This should work just fine with the ng-class variable. You won't even need to use addClass() or removeClass(), you can simply manipulate the variables from within your linking function. Here is an example usage:
<div ng-class={classToTarget: applyClass}>
Then inside your linking function you simply set applyClass to true|false based on whether you want the class applied to the div or not. classToTarget should be set to the name of the class you want to apply to the div.
The ng-class documentation has some really good examples covering this exact scenario. See https://docs.angularjs.org/api/ng/directive/ngClass for more information.

Related

Filter a directive by using a div wrapper or within the directive tag

I'm trying to go with the best approach and avoid unnecessary rendering/processing time in my AngularJS app when choosing between 2 directives to be displayed in the page inside an ngRepeat loop, want to know which is the best way:
If by setting the ng-if directly in the directive html element, like:
<div ng-repeat="element in list">
<my-directive-a ng-if="someFunction(element)"></my-directive-a>
<my-directive-b ng-if="!someFunction(element)"></my-directive-b>
</div>
Or by moving out the first <div> from the directive's template and use it as a wrapper for each directive. For instance:
<div ng-repeat="element in list">
<div ng-if="someFunction(element)">
<my-directive-a></my-directive-a>
</div>
<div ng-if="!someFunction(element)">
<my-directive-b></my-directive-b>
</div>
</div>
NOTE: The starting <div> element on each directive could be modified behave the same so I will basically take that out of the directive's html and moving it outside the directive declaration in order to place the ng-if there
What would be the best approach for this case? Are there any performance implications from doing it one way or another? Or is it just the same thing? Consider that the number of elements in the list could get really big.
They are quite the same, but you can improve performance with one-time binding, but only when element does not change at runtime (for example, let's say that it has property name, and your someFunction is like return element.name === 'John'). Angular just stop observing this function when it returns value, and watches will be deleted. There are 2 prerequisites to use this solution:
Elements properties in list does not change (if you rely on them in someFunction), for example if you rely on name property name must not change, because watcher on someFunction is note available.
When list changes or its elements properties change, you reload all list (for example, you fetch it from server again if you know that change occurred)
What you get with this? There is no watches after my-directives are drawn on ng-ifs, and when something changes, new reference is bound to list (for example, it comes from server) and everything will be redrawn, ng-ifs will run again and when will become stable (function returns value) then will be unbound. How it looks like? Like this:
<div ng-repeat="element in list">
<div ng-if="::(someFunction(element))">
<my-directive-a></my-directive-a>
</div>
<div ng-if="::(!someFunction(element))">
<my-directive-b></my-directive-b>
</div>
</div>
Two colons before expression. But be aware, that with one-time binding it's easy to mess up - you need to be sure that you test your code enough to be sure it works.

How to make proper container component using Angular?

In the project I work on there are list "manipulation controls", like:
The parts of this controls are the same at 90% of the pages. So I'm thinking about writing "manipulation controls" Component, so I wouldn't change sizes at every page, just in Component's template if I need to (all these col-xs-*), or just copy/paste html for each input separately.
<div class="row">
<div class="col-xs-7 form-inline">
<div class="col-xs-9">
<!-- Search input -->
</div>
<div class="col-xs-3">
<!-- Type select -->
</div>
</div>
<div class="col-xs-5 form-inline right">
<sort-by ng-model="sortBy" ng-change="setCurrentPage(1);" values="{{sortValues}}"></sort-by>
<items-per-page ng-model="itemsPerPage" ng-change="setCurrentPage(1);"></items-per-page>
</div>
</div>
Is it a good idea to make such "container" component? Is there any tutorial on how to make it properly (some of the inputs might be hidden, i.e. list is small and there is no need for pagination, every placeholder, title are unique in general, so there might be many variables to pass)?
This is more or less architecture question, I'm not experienced in this, but to my mind the idea of writing such component is good. If I'm mistaken or the question isn't specific enough, please argument it.
Yes, it is a good idea to turn reusable code into components.
Yes, passing configuration variables is how you would customize it for each use case. Using ng-show, ng-hide, ng-if, ng-switch, ng-class, ng-style, etc ... there are many ways to implement the options in your template.
When you have a large number of options, it is common practice to pass them as one object. (ie. config="{foo: 'bar', baz: 'biz'}" vs foo="bar" baz="biz").
Yes, it's a good idea: that's the purpose of directives (or components, in the new 1.5x implementations): inject in your HTML some reusable components in an intelligent way.
Think if you ever need to bind a variable to your "containers": you'll be able to do it easily and with no pain at all, by using directives/components.
Alternatively, if you don't need any form of logic inside your "containers", you could use ng-include with templates to inject html in your pages, like this:
<div ng-include"myContainer.html"></div>
and somewhere in your "templates.html"..
<script type="text/ng-template" id="myContainer.html">
<!-- content -->
</script>
What you are looking for is Angular directive (https://docs.angularjs.org/guide/directive)

Need some guidance on how to set up directives for a dynamic view

I am working on my first angular directive and still getting my head around the concepts and what's possible with directives. As I've been researching the best way to tackle this problem I haven't been able to identify an example that addresses what I'm trying to do, so thought I would ask for some help from the experts here.
I have an array of objects that are one of three types.
I would like to use the ng-repeat directive to iterate through this array and display the objects on the page.
Each object type has a different view associated with it as each object shares some properties, but also have unique properties.
I would like to set up a directive that displays the correct view based on the objective type.
So the logic would work something like the following:
<div ng-repeat="item in dataset">
<the-smart-directive>item</the-smart-directive>
</div>
One idea would be to have one directive where I determine the templateUrl based on the object type and then have a unique template for each of the objects.
Another idea would be to have a parent directive and then three other directives (one for each object type) and the parent directive would insert the correct object type directive (this is the idea that seems like the better approach, but I'm not sure how to actually implement this idea).
I'd love some help in understanding the best way to tackle this and how to implement. If you could provide some example code that would be wonderful and get me started on the right path.
Thanks for your help!
The way we are using it is with ng-switch inside the ng-repeat.
<div ng-repeat="item in dataset" ng-switch="item.type">
<directive-one ng-switch-when="1">
</directive-one>
<directive-two ng-switch-when="2">
</directive-two>
<directive-three ng-switch-when="3">
</directive-three>
</div>

Include behaviour inside ng-switch

I'm building a reasonably non-trivial Angular-js application for the first time and am trying to establish some intuition about how to get things done. Most things are making sense, but there's one pattern in particular that has me stumped -
Whenever I place an "include" style directive inside an ng-switch, it is ignored. I've experimented with just about every style of ng-switch, ng-include, and ng-transclude I can think of to achieve the desired behaviour, but to no avail. I haven't noticed any documentation indicating that this would be disallowed, nor any equivalent style of pattern.
Here is an example of what I have tried to do:
<div ng-switch="is_logged_in()">
<div ng-switch-when="true">
logged-in:
<div ng-include="'views/logout.html'"> </div>
</div>
<div ng-switch-default>
not-logged-in
</div>
</div>
The expected behaviour being that the logout form is displayed when $scope.is_logged_in() returns true.
The behaviour I see is that "logged-in:" is displayed, but the include isn't.
I've tried various versions of Angular-js. I've inspected the network traffic and seen that the include is in-fact being fetched, but I can't get this to work. I've had the same behaviour manifest when trying to build my own template control structures using directives.
The way I've seen most examples dodge this is by using JS in a directive to manually show/hide various sections of the transcluded content - is this really the idiomatic way to get the behaviour I'm looking for?
Thanks!
While using ng-include I always assign the path to a variable in controller.
$scope.logoutlink ='views/logout.html'
And in the view you can assign as
<div ng-include="{{logoutlink}}"> </div>
It would be helpful to post a JSfiddle link.

Is there a way to make AngularJS work with HTML-first?

Is there a way to have a HTML-view with pre-populated values from the server, and then get AngularJS to read those values into it's $scope?
I'm thinking of a scenario where the HTML is like this:
<div ng-controller="TestController">
<div ng-bind="title">Test Title</div>
<div ng-bind="itemCount">33</div>
<div ng-repeat="item in items">
<div ng-bind="item.title">Item 1 Title</div>
</div>
</div>
<button ng-click="update()">Update</button>
And the JavaScript is like this:
function TestController($scope) {
$scope.update = function() {
console.log($scope.title); // Should log "Test Title"
};
}
The thought behind this is to let the server render HTML that search engines can index, but have a JavaScript-model-representation of the content for manipulation through JS.
While ng-init is one solution, it requires you to explicitly set the value. So here is an alternative solution.
http://plnkr.co/edit/pq8yR9zVOHFI6IRU3Pvn?p=preview
Note : This solution wont work for ng-repeat. Control flow directives cant be used with this. But for simple extraction of information from ng-bind this works pretty well. All that you need to do is add the default directive ( code in plunk ) to wherever you are doing the bind and it will extract the text content and push it to the scope variable.
EDIT (solution with ng-repeat):
So, I was thinking of a way to make ng-repeat also work the same way. But getting ng-repeat to work like this isnt an easy job ( see the code for proof :P ). I have finally found a solution - here you go :
http://plnkr.co/edit/GEWhCNVMeNVaq9JA2Xm2?p=preview
There are a couple of things you need to know before you use this. This hasnt been thoroughly tested. It only works for repeating over arrays ( not objects ). There could be cases that have not been covered. I am overriding ngRepeat itself which could have other consequences. When you loop through the items ( in your server side code ) dont forget to add default="true" on the first element and default on the rest of the elements.
Hope this helps.
Add ng-init to your elements with the value so that it will work the way you want.
http://docs.angularjs.org/api/ng.directive:ngInit
I think what you really want is to make your application searchable by serving static files in parallell. Read more about it here http://www.yearofmoo.com/2012/11/angularjs-and-seo.html

Resources