Is it possible to nest ng-switch-when insides of ng-repeat?
<div ng-controller="UserController">
<div ng-switch on="renderPath">
<div ng-repeat="route in routes">
<div ng-switch-when="route.path">
<div ng-include src="route.url"></div>
</div>
</div>
</div>
</div>
I got the following exception when I run it:
Error: Argument '?' is required
pa#http://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js:16 ...
<!-- ngSwitchWhen: route.path -->
Thank you!
EDIT
What I am trying to accomplish is the following
<div ng-switch on="renderPath">
<div ng-switch-when="path1">
<div ng-include src="url1"></div>
</div>
<div ng-switch-when="path2">
<div ng-include src="url2"></div>
</div>
<div ng-switch-when="path3">
<div ng-include src="url3"></div>
</div>
</div>
</div>
So I was wondering if I can use ng-repeat to help ne reduce the redundant HTML template code (ng-switch-when) above.
No you can't nest them. ng-switch adds an entry to the $$watchers array on the ng-controller $scope. ng-repeat creates a new child scope for each iteration. When ng-switch-when is encountered, (I'm guessing here) it can't find any ng-switch information in the current $scope (which is now the ng-repeat child scope), so it fails.
Update: I looked into this some more. The error happens with 1.0.3, but not 1.0.4 (but it doesn't work with 1.0.4 either). What is actually going on is that the ng-switch-when scope is a child scope of the controller's scope, not the ng-repeat iteration child scope. Therefore, route is not visible to the ng-switch-when directives. Here's a fiddle that uses 1.0.4 -- you can click some links to see the controller, ng-repeat, and ng-switch-default scopes. Examining the ng-switch-default scope, you can see that its $parent is the controller's scope, not an ng-repeat scope.
I think ng-switch on should be followed by ng-switch-when. In your case you are having a
<div ng-repeat="route in routes">in between.
The logic you have shown does not require ng-switch or maybe i am missing something.
Related
My problem is related to placing the same component with different parameters on the same page. In this case it is a component containing a chart from a third party Javascript library (D3JS) which needs an HTML id attribute to locate and modify the component's HTML contents.
Now this id attribute should contain a unique string for each chart placed on the page, and if I directly set it as a string from the parent component it works just fine:
<my-chart id="gaugeChart0"></my-chart>
The reason it works is I guess, because the id attribute exists right at component creation time and whatever code is trying to access it can do that right away.
However this chart is in turn embedded into a bootstrap 4 card layout, like so:
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-5">
<my-chart id="gaugeChart0"></my-chart>
</div>
<div class="col-7">
... Some other widgets ...
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-5">
<my-chart id="gaugeChart1"></my-chart>
</div>
<div class="col-7">
... Some other widgets ...
</div>
</div>
</div>
</div>
</div>
</div>
Now to make it more convenient (and to easily bind to click events to the whole block etc.) I would like to extract the whole part beginning with <div class="card"> into a new component.
Let's say I call this new component WidgetContainerComponent which contains the chart as well as the bootstrap card layout including the other widgets defined there.
The resulting code when using this wrapper component would be:
<div class="row">
<div class="col-6">
<widget-container chartId="gaugeChart0"></widget-container>
</div>
<div class="col-6">
<widget-container chartId="gaugeChart1"></widget-container>
</div>
</div>
In order for that to work the WidgetContainerComponent has an input field
#Input() chartId: string;
that can be set.
What I want to do then is to set the id attribute of the MyChartComponent to the string that has been set to chartId:
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-5">
<my-chart [id]="chartId"></my-chart>
</div>
<div class="col-7">
... Some other widgets ...
</div>
</div>
</div>
</div>
But this does not work, as angular adds a prefix to the id attribute which results in something like ng-reflect-id.
I also tried setting the attribute with [attr.id] as described here and here:
<div class="card">
<div class="card-body">
<div class="row">
<div class="col-5">
<my-chart [attr.id]="chartId"></my-chart>
</div>
<div class="col-7">
... Some other widgets ...
</div>
</div>
</div>
</div>
This results in the MyChartComponent having a straight id attribute, but it seems to be only added at a later stage within the lifecycle of the component.
I also tried to initialize the chart within the MyChartComponent only in ngOnInit and ngAfterContentInit, but this does not work as well.
Any suggestions or ideas are very welcome!
So I found a solution to this problem. The problem was twofold:
The first problem was related to the requirement of having a genuine id attribute in contrast to the attribute name prefixed with ng-reflect- by angular.
What I didn't know is that from Angular 4, this prefix gets added to any attribute which is declared as an #Input variable for the component in development mode (for an in-depth explanation see this post).
The solution to this problem was to write [attr.id]=chartId instead of [id]=chartId. The reason is that in this case I needed to set an HTML Attribute, however using the square brackets notation I created a Property Binding. In order to dynamically set an HTML Attribute via the property binding syntax you have to add the prefix attr. to the attribute's name.
For a good overview regarding all valid binding syntaxes see the Angular Docs.
Specifically to review how to do attribute binding see this section.
The second problem was that I tried to access the id attribute of the component when it has not yet been created. This problem is related to the lifecycle hooks of Angular, where there are different stages. For a good overview of Angular's lifecycle hooks, see this page.
Because I didn't know it myself in detail, I will elaborate it here shortly.
Angular comes with a fixed set of lifecycle hooks which are called each time a component is set up and are also called in a predefined order. The hooks are defined as follows:
constructor
ngOnChanges
ngOnInit
ngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
ngOnDestroy
_
Important to note is that elements created or prepared in one step can only be accessed in any of the subsequent steps. In my case I put all the code for the initialization of the chart into the ngAfterContentInit hook, however the component is only fully loaded when ngAfterViewInit is called.
Finally the solution was to put the pre-initialization code into the constructor and to place the chart initialization code into the ngAfterViewInit method. At this stage the id attribute had been created properly and could be accessed by the chart.
I am using the following angular plugin to generate the query.
angular query builder
the issue I am getting is when I use the directive twice. one after another all the function if I use in first happens to another as well.
<div class="container" ng-controller="QueryBuilderCtrl">
<h1>Angular.js Query Builder</h1>
<div class="alert alert-info">
<strong>Example Output</strong><br>
<span ng-bind-html="output"></span>
</div>
<query-builder group="filter.group"></query-builder>
<query-builder group="filter.group"></query-builder>
</div>
Its a piece of code from index page of the plugin. Here I copy pasted the querybuilder directive twice. But its sharing the same scope.
How to fix this issue.
Try giving different model to directives. In your case they are sharing same model.
<div class="container" ng-controller="QueryBuilderCtrl">
<h1>Angular.js Query Builder</h1>
<div class="alert alert-info">
<strong>Example Output</strong><br>
<span ng-bind-html="output"></span>
</div>
<query-builder group="filter.group"></query-builder>
<query-builder group="filter.anotherGroup"></query-builder>
</div>
I don't really think I can elucidate much more than I already have in the title, it's a fairly self-descriptive question.
Say I have this structure:
<div ng-repeat="type in types">
<div ng-repeat="subtype in type.subtypes">
<div ng-repeat="item in subtype.items">
<span>How to access Controller scope here?</span>
</div>
</div>
</div>
Inside the span, how can I access the original scope on the controller?
In Knockout, you can do $parents[i] where i is however many scopes you want to step back up in. I haven't seen a reference to that being possible with Angular.
Do I really have to call $parent.$parent.$parent?
Do I really have to call $parent.$parent.$parent?
No:
<div ng-repeat="type in types">
<div ng-repeat="subtype in type.subtypes">
<div ng-repeat="item in subtype.items">
{{type}} {{subtype}} {{item}}
</div>
</div>
</div>
They all inherit from the top-level scope.
If you're worried about conflicting namespaces, checkout the controllerAs syntax:
<div ng-controller="ParentCtrl as parent">
{{parent.property}}
<div ng-controller="ChildCtrl as child">
{{parent.property}}
{{child.property}}
</div>
</div>
What happens if you have conflicting properties in different scopes? Which gets picked?
The one at the lowest level.
I need to create templates in handlebars for an html page and the whole html should go inside of templates. For e.g. I have:
<div class= "something-pull-left-something">
<div class="someclass">
<li a href= ''>Some more info and some more divs and spans and html code</li>
</div>
</div>
and I should create a big template for the first div ''something-pull-left-something'' and smaller templates inside of it for the other items and I cant quite understand how this should happen.
Divide it up into parts as it makes sense. Try to avoid having one huge template. Instead, make one template that includes a number of other templates. You may run into performance issues but worry about that later -- it is likely not an issue.
Make main template which contains header, body and footer.
Add partials to the main template.
If you wants to use Bootstrap then you can go through this http://getbootstrap.com/components
or you can use bootstrap class
<div class="container">
<div class="col-md-12">
//code
</div>
<div class="col-md-12">
<div class="col-md-6">
//code
</div>
<div class="col-md-6">
//code
</div>
</div>
</div>
I am making an application using AngularJS and want to be able to switch between "tabs" and swap back and forth different "partials" or html templates into a panel/container (using ngInclude).
Here's my template, which is wrapped inside a ngView.
<div class="row">
<div class="col-md-3">
<div class="list-group" data-fixed-sidebar data-nav-control>
<a href="#/analyze/option1" class="list-group-item" data-tab-route="/analyze/option1.*" >Analyze Option 1</a>
Analyze Option 2
Analyze Option 3
Analyze Option 4
</div>
</div>
<div class="col-md-9">
<div class="panel panel-default">
<div class="panel-body">
<div ng-include="child"></div>
</div>
</div>
</div>
</div>
The problem is, when I click on one of the links (for example, the first link which routes to #/analyze/option1) it will reload my controller and lose track of it's current state. I am using $route and $routeProvider and would prefer a solution that keeps using this module.
Controllers are meant to be ephemeral. The correct way (TM), in my opinion, to do it would be to put the necessary state in an service, which is initialized in a singleton fashion and will retain state between route changes.