What is the best way to do a bindings for a repeating view element?
Here is a view fragment currently implemented with underscore template.
How can I replace this block with backbone.stickit ?
<% _.forEach(model.estimates, function(estimate) { %>
<li class="list-item span12">
<span id='estimateNo'><%= estimate.estimateNo %></span>
<span id='name'><%= estimate.name %></span>
<span id='validity'><%= estimate.validity %></span>
<span id='grossPrice'><%= estimate.grossPrice %></span>
<span id='status'><%= estimate.status %></span>
</li>
<% }) %>
bindings: {
'#estimateNo': ???,
'#name': ???,
'#validity': ???,
'#grossPrice': ???,
'#status': ???
}
I answer my own question...
there is a design issue with my view, i should move the content of the loop into a sub-view and use stickit for each individual view.
The loop should be in the code and not in the template ...
Related
I am trying to set a variable to template with if in the HTML. The issue is that I can't see my template and don't have any errors from the logs. I can see that elements are in the HTML but still can't see it.
The template is:
<div class="list-group">
<div id="table_template">
<div id ="table"></div>
<script type="text/template" id="nextPage">
<% if (nextLink != "") { %>
<nav><ul class="pager"><li><a href="#" id="next_page" >Next</a></li> </ul> </nav>
<%}%>
</script>
</div>
</div>
</div>
and the view:
var template = _.template($('#nextPage').html());
view.$el.find('#nextPage').html(template(listSongs));
Update: Looks like I am unable to see it if I have script tag.
A script tag is used so that the browser does NOT render that piece into the whole DOM. You did that assuming that the script tag will print into the view but it won't. You will need to inject it into the view. Try this:
<div class="list-group">
<div id="table_template">
<div id ="table"></div><div id="nextPage"></div>
<script type="text/template" id="nextPageTemplate">
<% if (nextLink != "") { %>
<nav><ul class="pager"><li><a href="#" id="next_page" >Next</a></li> </ul> </nav>
<%}%>
</script>
</div>
</div>
Then in your view it can look like this:
var template = _.template($('#nextPageTemplate').html());
view.$el.find('#nextPage').html(template(listSongs));
Now I'm unsure if your view El is "list-group" (but I hope it is).
In my ng-repeat, i require the DOM to be switched, according to the active status.
i tried like this, but not working for me:
<ul>
<li ng-click="activate(item)" ng-repeat="item in items" ng-class="{active : active == item}">
<span ng-if="item==active">
<span>{{item}}</span><!-- when active nested under span -->
</span>
<!-- else without nesting the span -->
<span ng-if="item== !active">{{item}}</span> //this is not working
</li>
</ul>
Live Demo
Replace your last ng-if statement to this (you've just made syntax error):
<span ng-if="item !== active">{{item}}</span>
Your active variable isn't boolean, so you can't toggle it in your statement.
Here is my use case
<li ng-repeat="item in heterogeneousFruitArray">
<div ng-if="item.type == 'apple'">
... custom apple stuff ...
</div>
<div ng-if="item.type == 'orange'">
... custom orange stuff ...
</div>
... stuff for all fruits ...
</li>
It would increase readability if I could say
<li ng-repeat="item in heterogeneousFruitArray">
<div ng-if="item.type == 'apple'">
<span ng-with="item as apple">
<h1>{{apple.name}}</h1>
Crispness: {{apple.crispness}}
... and so on...
</span>
</div>
...
</li>
Is there a way to do this with angular?
I realize that this pattern could be me coding with an accent because of my django templates background. If I'm miles away from 'how it's done in angular', please let me know.
ngInit was designed with aliasing in mind, especially within an ngRepeat:
<li ng-repeat="item in heterogeneousFruitArray">
<div ng-if="item.type == 'apple'" ng-init="apple=item">
... custom apple stuff ...
</div>
<div ng-if="item.type == 'orange'" ng-init="orange=item"">
... custom orange stuff ...
</div>
... stuff for all fruits ...
</li>
Here is official documentation on ngInit:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Demo Plunker
In tandem with ngInit for aliasing, you should also consider using ngSwitch, instead of having multiple ngIfs where only one is evaluated to true at a time.
Using ngSwitch has the same result, but increases readability and is more efficient as it evaluates the condition once in every digest loop (in contrast to multiple ngIfs where the same expression is evaluated once for every ngIf).
E.g.:
<li ng-repeat="item in heterogeneousFruitArray">
<div ng-switch="item.type">
<!-- Apple-specific template -->
<span ng-switch-when="apple" ng-init="apple=item">
<h1>{{apple.name}}</h1>
Crispness: {{apple.crispness}}
</span>
<!-- Orange-specific template -->
<span ng-switch-when="orange" ng-init="orange=item">
<h1>{{orange.name}}</h1>
Juicy-ness: {{orange.juicyness}}
</span>
<!-- Default template (used when `item.type` is unknown/unexpected) -->
<span ng-switch-default ng-init="unknown=item">
<h3>What kind of fruit is "{{unknown.type}}" ???</h3>
</span>
</div>
</li>
You can always use AngularJS Filters to implement that.
Html:
<div ng-app='myApp' ng-controller='myCtrl'>
<ul>
<li ng-repeat='item in items | filter:{name: "orange"}'>
{{item.id}} - {{item.name}}
</li>
</ul>
</div>
Js:
var app = angular.module('myApp',[]);
app.controller('myCtrl', function($scope){
$scope.items = [
{
id: 12,
name: 'apple'
},
{
id: 13,
name: 'orange'
},
{
id:14,
name:'grape'
}
];
});
JSFiddle.
In AngularJS, to simply show a field through an a tag, I would do in this way:
<div ng-show="aField">Content of aField</div>
<a ng-click="aField=true">Show aField</a>
until here, no problem.
I would like now to put more buttons and fields so that, when I click on A it shows the content of A, then when I click on button B, content of A disappears and content of B appears.
How can I do this? Thank you.
UPDATE
Thank you everyone for your solutions, they works! Now, I am doing a template for every content of and because I have much data to show but all in the same structure.
Here the index.html
<div ng-model="methods"
ng-include="'templateMethod.html'"
ng-repeat = "method in methods">
here the script.js:
function Ctrl($scope) {
$scope.methods =
[ { name: 'method1',
description: 'bla bla bla',
benefits: 'benefits of method1',
bestPractices : 'bestPractices',
example: 'example'},
{ name: 'method2',
description: 'bla bla bla',
benefits: 'benefits of method2',
bestPractices : 'bestPractices',
example: 'example'} ];
}
and here the templateMethod.html:
<table>
<tr>
<td>
<div ng-show="toShow=='{{method.name}}Field'">
<h3>{{mmethodethod.name}}</h3>
<p>
<strong>Description</strong>
{{method.description}}
</p>
<p>
<strong>Benefits</strong>
{{method.benefits}}
</p>
<p>
<strong>Best practices</strong>
{{method.bestPractices}}
</p>
<p>
<strong>Examples</strong>
{{method.example}}
</p>
</div>
</td>
<td class = "sidebar">
<ul>
<li><a ng-click="toShow='{{method.name}}Field'" class="{{method.name}} buttons">{{method.name}}</a></li>
</ul>
</td>
</tr>
</table>
It works!
But: if I click the first button and then the second one, the content of the first button do not disappear, it appears under the content of the first button...
Problem with the repetition?
Thanks
It might be better to handle more complex logic in the controller, but in general think about the content of the directive strings as normal js:
<div ng-show="aField">Content of aField</div>
<div ng-show="bField">Content of bField</div>
<a ng-click="aField=true; bField=false">Show aField</a>
<a ng-click="aField=false; bField=true">Show bField</a>
Or use ng-show in concert with ng-hide:
<div ng-show="aField">Content of aField</div>
<div ng-hide="aField">Content of bField</div>
<a ng-click="aField=true">Show aField</a>
<a ng-click="aField=false">Show bField</a>
In the former strategy, nothing shows upon page load. In the latter, the bField content shows by default. If you have more than two items, you might do something like:
<div ng-show="toShow=='aField'">Content of aField</div>
<div ng-show="toShow=='bField'">Content of bField</div>
<div ng-show="toShow=='cField'">Content of cField</div>
<a ng-click="toShow='aField'">Show aField</a>
<a ng-click="toShow='bField'">Show bField</a>
<a ng-click="toShow='cField'">Show cField</a>
I'm guessing that you have a list of items and want to show each item content. Something an accordion component does.
Here is a plunker that shows how you could do it: http://plnkr.co/edit/UTf3dEImiDReC89vULpX?p=preview
Or if you want to display the content on the same place (something like a master detail view) you can do it like this: http://plnkr.co/edit/68DJHL582oY4ecSiiUdE?p=preview
simply use one variable which content is visible. http://jsfiddle.net/gjbw7/
<a ng-click="show='a'">Show aField</a>
.
<div ng-show="show=='a'">Content of aField</div>
I would recommend to create a service in case your fields belong to different controllers.
Service:
App.factory('StateService', function() {
return {
openPanel: ''
};
});
Injecting the service in a Controller:
App.controller('OneCtrl', function($scope, StateService) {
$scope.stateService = StateService;
});
Finally using it a view:
<a ng-click="stateService.openPanel='home'">Home</a>
<div ng-show="stateService.openPanel == 'home'">Content of Home</div>
Demo: http://jsfiddle.net/codef0rmer/BZcdu/
Try this way.
<div>{{content}}</div>
<a ng-click="content='a'">Show aField</a>
<br>
<a ng-click="content='b'">Show bField</a>
<br>
<a ng-click="content='c'">Show cField</a>
<br>
<a ng-click="content='d'">Show dField</a>
<br>
<a ng-click="content='e'">Show eField</a>
<br>
<a ng-click="content='f'">Show fField</a>
Take a look at the ng-switch directive.
<div ng-switch="aField">
<div ng-switch-when="someValue1">
HTML content that will be shown when the aField variable value is equal to someValue1
</div>
<div ng-switch-when="someValue2">
HTML content that will be shown when the aField variable value is equal to someValue2
</div>
<div ng-switch-default>
This is where the default HTML content will go (if aField value is not equal to any of the ng-switch-when values)
</div>
</div>
<div class="company_name" ng-controller="CompanyName">
<h1 class="left">
{{data.company_name}}
</h1>
</div>
What I'd like to do is make it so that if data.company_name hasn't been added through an input field, it shows a placeholder "Company name", how can that be done using angularjs?
You can use ng-if and do something like
<div class="company_name" ng-controller="CompanyName">
<h1 class="left">
<span ng-if="data.company_name === ''">
// Some placeholder
</span>
<span ng-if="data.company_name !== ''">
{{data.company_name}}
</span>
</h1>
</div>
BTW ngIf is a new directive added in v1.1.5 so you might need to upgrade your angular version
See my plunker here : http://plnkr.co/edit/qiN2XshEpay6e6zzhUKP
One way to keep the code clean is to use a filter. This piece of code adds a class to an active tab.
var filters = angular.module('filters');
filters.filter('ie', function(){
return function(v, yes, no){
return v ? yes : no;
};
});
Template
<li class="{{activeTab == 'home' | ie: 'active-class':''}}">
Home
</li>
For Using ng-if, ng-else-if, and ng-else in your project use this:
https://github.com/zachsnow/ng-elif
You can use ng-if condition for the check company name vlaue. Let's take example of
<span ng-if="driver.status_flag == 1">
<i ngif="{{driver.status_flag}}" class="icon-ok-sign icon-2x link" style="color:#090" href="#" title="Payment received" ></i>
</span>
In above example I have added condition status_flag value is 1 then the inside span value will show. Same way with your case you can add statement like
<span ng-if="data.company_name === ''">
<i ngif="{{driver.status_flag}}" class="icon-ok-sign icon-2x link" style="color:#090" href="#" title="Payment received" ></i>
</span>