Include behaviour inside ng-switch - angularjs

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.

Related

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)

What is the advantage of "Controller as" in Angular?

What is the advantage of using "Controller as" syntax in Angular? Is it just to create an alias for a controller or does it have some other technical reasons behind the scenes?
I am new to Angular and want to know more about this syntax.
controllerAs-syntax has multiple advantages:
Clartiy
Consider the following example:
<div ng-controller="containerController">
<h2>Improve your life!</h2>
<p ng-controller="paragraphController">
We talk about {{topic}} a lot, but do we really understand it?
Read this article to enhance your knowledge about {{topic}}
</p>
</div>
Just by reading this piece of code, you can not tell where topic comes from. Does it belong to the containerController, to the paragraphController or is it just a random floating scope variable from sone input above?
By using controllerAs it is very clear:
<div ng-controller="containerController as container">
<h2>Improve your life!</h2>
<p ng-controller="paragraphController as paragraph">
We talk about {{paragraph.topic}} a lot, but do we really understand it?
Read this article to enhance your knowledge about {{paragraph.topic}}
</p>
</div>
You can immediately see that topic is a property of paragraphController. This makes code a lot more readable overall, as it forces the developer to make clear who the functions and variables in the scope belong to.
Binding to properties
When you are using the old controller syntax, strange things can happen when you have multiple bindings in different scopes to the "same" variable. Consider this example:
<form ng-controller="myFormController">
<input type="text" ng-model="somefield">
<div ng-controller="someOtherController">
<input type="text" ng-model="somefield">
</div>
</form>
It looks like both inputs are bound to the same variable. They are not. Everything looks like it works fine when you edit the first input first, but as soon as you edit the second one, they won't sync up anymore. This has to do with the way scope-inheritance and binding work(and there is an excellent answer on this on SO). This does not happen when you bind to object properties (aka when there is a . in your ng-model-attribute). With controllerAs you bind to properties of the controller objects anyways, so it naturally solves that problem:
<form ng-controller="myFormController as myForm">
<input type="text" ng-model="myForm.somefield">
<div ng-controller="someOtherController as other">
<input type="text" ng-model="myForm.somefield">
</div>
</form>
It gets rid of scope(mostly)
The use of scope to create bindings to controllers in old angular code is hard to read, hard to understand and completely unnecessary if you use controllerAs. You no longer have to inject scope into every single controller, in fact you will probably not inject it in any in most applications (you still need to do so if you want to use the angular event system). This results in cleaner controller-code with less strange boilerplate.
It prepares for Angular 2
In angular 2, scope will be gone and we will write everything as components. Using controllerAs lets you work without scope and forces you to think more component-oriented, thus preparing you (and the applications you eventually will want to migrate) for the 2.0 update.

AngularJS Animations ng-switch ng-repeat

I am trying to do what looks like a simple process: to display a list of items received from an HTTP request with animation.
First of all, here is my way of doing it ( I am open to any suggestions to do it in a better angular way ):
I define a scope variable state that I initialize to loading in my controller and that I change to loaded when I receive data from the HTTP request.
I initialize a scope variable items with the received data.
In my view, I use ng-switch for the states, and ng-repeat with the items.
I define an animation with css on ng-repeat.
Here is a plunkr ( with a $timeout instead of the request ).
I cannot understand why the animation does not work.
Any help will be appreciated. Thanks.
The reason it is happening is because your ng-when. The same thing happens with ng-if, but would work fine if you used ng-show.
The problem is that when your ng-when condition returns true, the ng-when first renders it's content in a detatched dom (so animations do not happen). This dom is then attached to the dom tree (this step is animated but you would have to put your animation class on the ng-when).
When using something like ng-show or ng-hide things work as expected because the dom is always attached (it is simply shown/hidden).
This might be considered either a bug or a limitation of ng-animate, you might want to post a github issue and see if the angular guys have any thoughts.
It seems to be a "feature" of angular that it won't add .ng-enter to repeat items inside ng-switch-when block. You can remove ng-switch-when="loaded" and it will work (You don't really need it as ng-repeat won't do anything if there is no items)
<div ng-switch="state">
<div ng-switch-when="loading">
<p>Please wait...</p>
</div>
<div >
<ul ng-repeat="item in items" class="animate-items">
<li>{{item}}</li>
</ul>
</div>
</div>
http://plnkr.co/edit/ocEj7BSQPSeIdnnfAOIE?p=preview

How to kill image flash in AngularJS

I'm trying to use AngularJS built-in directives to achieve some simple JS effect without writing actual js code. It actually works pretty well, except the initial flash.
I know to deal with text, people should use ng-bind instead of {{}}
But how do you deal with directives like ng-if?
Here is my code:
<li ng-if="!magazines.resolved"> <!-- add "&& isOwner" when done -->
<dl>
<dt ng-model="changeToActivation" ng-init="changeToActivation=false" ng-mouseover="changeToActivation=true" ng-mouseleave="changeToActivation=false"><img ng-if="!changeToActivation" ng-src="<?php echo base_url('public/images/system_icons/add_magazine.jpg');?>">
<img ng-click="addMagazine()" id="activated" ng-if="changeToActivation" ng-src="<?php echo base_url('public/images/system_icons/add_magazine_activated.jpg');?>"></dt>
<dd class="magazineName">Create <br> A new magazine</dd>
<dd class="publishDate">Now!</dd>
</dl>
</li>
I know it gets a bit hard to read, but it's very easy. There is a model defined on <dt></dt> tag. If mouse is over this tag, the model value becomes true; when leaves, it becomes false.
Based on this boolean model value, one or the other image will be shown.
It works like a charm, but I can see both images at the very beginning, flashing!
How to deal with something like this then?
ngCloak may help, but you should also use ng-src for the actual image source, this will prevent your site from loading the image before the model has received a value. Also when using ngCloak, you may need to load the AngularJS source at the top of your html file as it may try to load the image before it knows what to do with the ng-cloak directive.
Applying ngCloak to you dt should do the trick for you: http://docs.angularjs.org/api/ng.directive:ngCloak
Here's an example from the docs. Note that it's added in two places- the directive as well as a class. The class is only needed for IE7 support.
<div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>

How to prepopulate ngModel in AngularJS

I have no idea how to pre-populate an ng-model in this circumstance that I have to use ngBind. I tried ng-init, but it's not working.
<h6 ng-show="isOwner" ng-bind="currentMagazine.magazine_name"
contenteditable ng-model="currentMagazine.magazine_name"
ng-change="update()"></h6>
I have a seperate directive that binds contenteditable attributes to ngModelController.
The problem now is whenever I update the model, ng-bind will jump out and refresh the div element, resulting in the cursur going back to the beginning of the text, which makes it impossible for any user to type.
I tried ng-init in a fashion like this:
<div ng-init="magazineName = currentMagazine.magazine_name">
<h6 ng-show="isOwner"
contenteditable ng-model="magazineName"
ng-change="update()"></h6>
</div>
It's not working. If I don't use ng-bind, then no text will show up.
Also I notice it might be related to this problem, when I type with space or delete key, they are escaped into HTML entities...so you get result like this:
Hopefully both of my problems can be solved! Thank you (it's a very frustrating day)!
In your app.js do this:
$scope.magazineName = $scope.currentMagazine.magazine_name;
In your HTML do something like this:
<input
ng-show="isOwner"
contenteditable
ng-change="update()"/>
or
<h6 ng-show="isOwner"
contenteditable
ng-model="currentMagazine.magazine_name"
ng-change="update()">
{{currentMagazine.magazine_name}}
</h6>
... though perhaps not, it's a bit difficult to gauge without seeing it... please make a jsfiddle or plunkr if you'd like to get more eyes on it.
If you're just trying to make some large text that is still editable and bound to the model it may be easier to just style an input for your needs.
Decided to play with contenteditbale since it's chance for me to learn something too... I can't seem to recreate the issue though:
http://jsfiddle.net/VSJQX/
I saw after doing this it wasn't updating the model, found another SO post that resolves that and included the changes here:
http://jsfiddle.net/VSJQX/2/

Resources