AngularJS rendering different template inside ng-repeat using ng-view - angularjs

I would like to apologize that I couldn't provide any code snippet regarding this question, I am a newbie about AngularJS.
<div ng-repeat="item in list" ng-view></div>
Using the code above, would it be possible to render different template which would be dependent on item.type property. I was expecting a result like this:
item.type == "image" returning: <div><img src="'IMAGE_URI'"></div>
item.type == "text" returning: <div><p>TEXT</p></div>
As of now I have create a template html for the enumeration of item.type. Is this concern possible using AngularJS? I've recently learned that ng-view accompannied with ng-route.

I think one way you can do it is to use 'ng-if' to conditionally include html:
<div ng-repeat="item in list">
<div ng-if="item.type == 'image'><img src="'IMAGE_URI'"></div>
<div ng-if="item.type == 'text'><div><p>TEXT</p></div>
</div>

You can have only one ng-view,
take a look at this answer.
from the documentation for ng-view:
ngView is a directive that complements
the $route service by including the rendered
template of the current route into the main
layout (index.html) file.
Every time the current route changes,
the included view changes with it according
to the configuration of the $route service.
Requires the ngRoute module to be installed.
What you're looking for is ng-include, combined with ng-switch,
take a look at this answer on how to combine the two.
ng-include creates a new child scope, which in turn inherits from the controller.
have a look at this answer for more information about the topic.

Related

How to better organize dynamic loaded directives in angular?

In my project, I have a small div that has 3 options "food", "drinks", "social". These are tied to a scope variable "$scope.option" on "AppController".
I have a series of ng-switch statements:
<div ng-switch on="option">
<div ng-switch-when="food">
<fooddirective></fooddirective>
</div>
<div ng-switch-when="drinks">
<drinksdirective></drinksdirective>
</div>
<div ng-switch-when="social">
<socialdirective></socialdirective>
</div>
</div>
Note that whatever option is selected, the food, drink, or social, these only take up half the page so they are all surrounded by "AppController". My intent is to be able to "Dynamically load directives" into the page. Is there a way I can get rid of the need to have to explicitly write "<socialdirective></socialdirective>" or maybe even get rid of all of the ng-switch? Or is there some better alternative? It feels like it could get very messy if I have say 20 or 30 of these options (i.e. food, drinks, social, games).
If I know the name of the directive in advance, say "food", "drinks", "social". Is there some way I can do something like:
<div ng-switch on="option">
// code that interprets option's variable (i.e. food), appends the text "directive" after, and dynamically/lazily add it in and remove it so it behaves like an ng-switch
</div>
I am not sure if it is possible, but am looking for any better alternative to what I am doing now. Any examples of a revised way of doing is great.
You can use UI router to accomplish this:
--index.html
<body>
Top Level
<div ui-view></div>
</body>
--optionsPage.html
<select ng-options="option.name for option in data.availableOptions track by option.id" ng-model="data.selectedOption"></select>
<div ui-view></div>
In the options page, you will make the select options generate ui-sref links to each type of directive you want to display. Child states will only change the ui-view of their parent state, so you can easily route to the correct directive.
Then you define your routes as such:
.state('options.food', {
templateUrl: "partials/options.food.html"
})
.state('options.drinks', {
templateUrl: "partials/options.drinks.html"
})
Then you can define the directive in each of those HTML files.
(Much of this code is just taken from the Angular and UI-Router code examples, but hopefully you can see what you need to do.)
UI Router - https://github.com/angular-ui/ui-router
If those directives have a lot of functionality in common, to me it seems that the best alternative would be to implement a new directive, say optiondirective, that encapsulates this behavior. This way you would just insert that directive on the html with the chosen option as the attribute, the ng-switch or whatever resolution mechanism you end up using would be hidden in the template of that directive, and the common functionality would be implemented in that directive's controller. That doesn't help you get rid of the hideous part, but at least you will get to re-use a greater portion of the implementation and modularize your code.
WARNING: I am not giving you a complitely working answer.. just want to give you an idea on how to do it.
you can create another directive which wraps the original one
.directive("wrapper", function(){
return {
scope: {'option': #},
template: '<' + option + 'directive>' + '</' + option + 'directive>'
}
})
and then call it like
if this does not work you will need to compile the html in your like function like below
var tmpl = '<' + option + 'directive>' + '</' + option + 'directive>'
element.html(tmpl );
$compile(element.contents())(scope);
that should definitely do it

Variable value as directive/controller name inside template (with $compile/$interpolate)?

I am creating a directive in which template I need to use the a scope's variable value as the name of the directive (or alternatively controller) to load.
Say I have a directive widget that has a template called widget.html which looks like:
<div class="widget widget.type" {{widget.type}} ng-controller="widget.type">
<div class="navBar">
<div ng-include="widget.type + '-t.html'"></div>
<i class="fa fa-close"></i>
<hr>
</div>
<div ng-include="widget.type + '-f.html'"></div>
</div>
Now widget.type is not getting evaluated in the first line. It works fine for ng-include. Say widget.type's value is weather. The first line should then be interpolated first to look like (doesn't matter if class attribute, widget.type-attr or ng-controller is interpolated)
<div class="widget" weather>
and then compiled to include the weather directive.
How can I get widget.type interpolated in the template?
Not an option is to use ng-include to load the directive. I need to use one common template for the widget and want to add/override/extend the base directive with additonal functionality/Variables.
If this is not the way to achieve that, is there a way to extend a directive the OOP-way?
See the plunkr
You can only place interpolation expressions in text nodes and attribute values. AngularJS evaluates your template by first turning it into DOM and then invoking directive compilation, etc. If you try to place {{...}} instead of attribute name, you'll just end up with messed-up DOM.
If you really need to replace a whole directive based on $scope variable value, you'll need to create a directive for application of other directives and do some heavy lifting with $compile (you'll have to completely re-compile the template each time the value changes). I'd recommend trying to find other designs solving your situation before attempting this.
For adjusting your template based on element attributes, see this answer.

AngularJS + Twitter Popover: Content Iteration

I'm using twitter bootstrap with a popover and got a AngularJS scoped variable to appear correctly. The below works.
(data-content="{{notifications[0].user}} shared {{notifications[0].user_two}}'s records")
When I add the following
(data-content="<b>{{notifications[0].user}} shared {{notifications[0].user_two}}'s records</b>")
No errors show up, but all of the {{}} no longer render.
So I tried this as a test of sorts
(data-content="<div ng-repeat='item in notifications'>test {{item}} <br/><hr/></div>")
Much like the last example, I see the "test" but not the {{item}}. And the "test" only show s up once, even though the notifications had three elements. When I look at the DOM there's this
<div class="popover-content">
<div ng-repeat="item in notifications">you <br><hr></div>
</div>
I've also tried just creating a directive to iterate through the array and make the output I want, but my attempt to set data-content equal to a directive have been failures. The examples I've found elsewhere I'm confident would work, but I just wanted to confirm before I begin implementing something like this (http://tech.pro/tutorial/1360/bootstrap-popover-using-angularjs-compile-service) or (Html file as content in Bootstrap popover in AngularJS directive) that I'm not missing a straightforward fix to the problem I outlined above that would not require me creating a directive.
Edit:
Plunkr Url http://plnkr.co/edit/VZwax4X6WUxSpUTYUqIA?p=preview
html might be breaking it, try marking it as trusted html using $sce
How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+
$scope.html = '<ul><li>render me please</li></ul>';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
<button ... data-content="trustedHtml" ...> </button>

Is there a different way to hide a scope variable from showing while AngularJS is loading?

I am using this way:
<div ng-cloak>{{ message.userName || message.text }}</div>
Is this the only / best way to ensure the user does not see the {{ }} when AngularJS is still loading ?
There are several ways to hide content before Angular has a chance to run
Put the content you want to hide in another template, and use ngInclude
<div ng-include="'myPartialTemplate.html'"></div>
If you don't actually want another request made to the server to fetch another file, there are a couple of ways, as explained in the $templateCache docs. There are tools to "compile" external HTML templates into JS to avoid having to do this manually, such as grunt-angular-templates.
Similar to ngInclude, if you put everything in custom directives, with its own template, then the template content won't be shown until Angular has had a chance to run.
<my-directive></my-directive>
With a definition of:
app.directive('myDirective', function() {
return {
restrict: 'E',
template: '<div>Content hidden until Angular loaded</div>'
}
});
ngBind as an alternative to {{}} blocks
<div>Hello <span ng-bind="name"></span></div>
ngCloak as you have mentioned (in this list for completeness).
<div ng-cloak>Content hidden until Angular compiled the template</div>
But you must have certain styles loaded before the page is rendered by the browser, as explained in the ngCloak docs.
You can use ng-bind too as the documentation explains.
A typical advantage about ng-bind is the ability to provide a default value while Angular is loading (indeed, ng-cloak can only hide the content):
<p>Hello, <span ng-bind="user.name">MyDefaultValueWhileAngularIsLoading<span/></p>
Then as soon Angular is loaded, the value will be replaced by user.name.
Besides, ng-cloak is useful when dealing with blocks (many HTML lines) and ng-bind on a particular element.

Angularjs : dom manipulation replacing and then reattaching to another parent with map

PROBLEM
I have a dom element, which i want to detach it from its parent and append it at some other location in the dom, angularjs way.
i could easily do this in jquery with detach and appendto, but i am unable, to find the same in angularjs way.
var detached = jQuery('.toBeDetached');
jQuery('.itemMaximixed').append(detached);
Note i need to detach since the element contains a map in it.
It may not be applicable in your case, but you can use the transclude facility of an Angular directive to do this.
I don't think attaching and deattaching would work. What I can suggest is destroying the recreating the template under different node.
You can use something like ng-if in Angular 1.1.5 for this. Using multiple ng-if and associated conditions you can bind the same template at multiple location, which ever ng-if returns true that template would get loaded.
The template code can be duplicated or be out inside a ng-template script. Something like this
<div id='parent'>
<div id='child1'>
<div ng-if='condition1'><ng-include src='datatemplate' /></div>
</div>
<div id='child2'>
<div ng-if='condition2'><ng-include src='datatemplate' /></div>
</div>
</div>
<script id='datatemplate' type='text/ng-template'>
<!-- Template HTML -->
</script>

Resources