How to bind multiple classes with ternary conditions? - ember.js

Assume labelCls, mandatory and optional are predefined CSS classes.
Sample Code:
<div {{bind-attr class=":labelCls (isRequired == "required"?mandatory:optional")}}>
Warning!
</div>
Wanted to be if isRequired = "required";
<div class="labelCls mandatory">
Warning!
</div>

Install ember-truth-helper addon for eq helper
<div class={{if (eq isRequired 'required') 'labelCls mandatory' 'labelCls optional'}}>
Warning!
</div>

Based on your comments, it sounds like you want to do this inside a component. So...
You can have a component that's defined as follows:
App.ReqClassComponent = Em.Component.extend({
isRequired: function(){
var someParam = this.get('someParam');
return someParam === 'required';
}.property()
});
Then, you can call the component in your template as follows:
{{ req-class someParam='required' }}
Working demo here

Related

How should I reload model from child controller in emberjs?

I am having problem while trying to update the model values, when PendingActionController.updateStage method is called I need it to update the related model & reflect the updated values. If I create another method in PendingController like ShowMessage it displays the alert.
Please explain What approach should I use?
For example, following is the code:
<script type="text/x-handlebars" id="pending/_actions">
<div class="content-actions">
<h2>Pending Actions</h2>
<ul>
{{#each pendingstages}}
<li>
{{#unless refreshingStage}}
{{render 'pendingAction' this}}
{{/unless}}
</li>
{{/each}}
</ul>
</div>
</script>
<script type="text/x-handlebars" id="pendingAction">
<div class="actionsBox">
<div class="actionsBar">
<div {{bindAttr class=":actionStatus completed:blue:green"}} {{action updateStage this}}> </div>
</div>
<div class="clear-both"></div>
</div>
</script>
PendingController:
App.PendingController = App.BaseObjectController.extend(App.ActionsControllerMixin, {
needs: ['application'],
postRender: function () {
//Some code here....
},
pendingstages: function(){
return App.PendingStage.find({Id: this.get('model.id')});
}.property('model.id', 'model.#stages.completed', 'refreshStage'),
ShowMessage: function(){
alert('Inside Sohw message.');
},
});
PendingActionController
App.PendingActionMixin = {
isEditing: false,
canDelete: true,
canEdit: true,
toggleIsEditing: function(){
this.toggleProperty('isEditing');
}
};
App.PendingActionController = App.BaseObjectController.extend(App.PendingActionMixin, {
needs: 'pending',
postRender: function(){
//some code here...
},
updateStage: function(stage){
var self = this;
this.get('controllers.pending').send('pendingstages');
},
});
EDIT (1):
Followignt are the versions of Ember & ember-data:
ember-1.0.0-master.js
ember-data-master.js: CURRENT_API_REVISION: 12
Problem can be solved by using store.fetch instead of store.find.
store.fetch always calls the API, whether that particular data exists in local ember-data store or not. Use it like this..
pendingstages: function(){
return App.PendingStage.fetch({Id: this.get('model.id')});
}.property('model.id', 'model.#stages.completed', 'refreshStage'),
See ember-data/store.js code. It is deprecated now. But you'll find new methods instead of this.

have Ember.TextField observe a change in a property inside an array

I have an array of Objects in the view that supposed to represent a dynamic number of fields in the .hbs
So the array is:
export default Ember.View.extend({
metadata_queries: [{name: '', type: 'Exists',
disableValue: true, queryValue:''}
/*, {...}, {...} */],
});
The rest of the array elements will be added dynamically
I have a Ember.TextField in the .hbs that needs to be disabled (or hidden - whichever is easier) according to disableValue (that changes by observing the type that is bound to an Ember.Select.
The code:
{{#each view.metadata_queries}}
<div class="form-group">
<div class="col-xs-2 col-xl-2">
{{view Ember.Select content=view.metaTypes selection=type}}
</div>
<div class="col-xs-2 col-xl-2">
{{view Ember.TextField classBinding=":tests-query" value=queryValue disabled=disableValue}}
</div>
</div>
{{/each}}
The thing is that disableValue is not a property - so the view doesn't get updated (I checked - the boolean itself does change)
How can I do that?
Made a JSFiddle to examplify:
http://jsfiddle.net/6Evrq/400/
Well... aparrently I didn't update disableValue properly:
The proper way to do it is:
this.get('metadata_queries').forEach(function(item, index, metaQueries) {
Ember.set(item, "disableValue", item.type === "Exists");
});
to make disableValue a property, it has to be wrapped in an Ember Object, like so
metadata_queries: [Ember.Object.create({name: '', type: 'Exists',
disableValue: true, queryValue:''})
/*, {...}, {...} */],

Different layouts depending on sub resources

Sorry if this is a really obvious questions but I have the following routes:
Web.Router.map(function () {
this.resource('orders', function(){
this.resource("order", {path:":order_id"});
});
});
And for my orders template I have something like:
<div class="someclass">
{{outlet}}
</div>
And what I want todo is:
{{#if onOrderRoute}}
<div class="someclass">
{{outlet}}
{{else}}
<div class="someotherclass">
{{/if}}
</div>
I was wondering what the best way of doing this is, or am I mising something?
There are multiple ways to accomplish this. The view has a layoutName property you can use to specify your layout. Another option is to specify a property on your child view, and then your template can bind to that by using the view property.
For example:
Web.OrderView = Ember.View.extend({
childView: true
);
Then, in your template you bind to view.childView
{{#if view.childView}}
<!-- code goes here -->
{{/if}}
Further, you can even create a mixin and then just inject that mixin into every view.
Web.ChildViewMixin = Ember.Mixin.create({
childView: true
});
Web.ChildView = Ember.View.extend(ChildViewMixin, {
});

angularjs - How to lazy load templates from templateCache in directive

I am trying to display the details of items in a list. This should be done by lazy loading the template (DOM for the details), because the template is very large and i've got many items in the list so a ng-show with ng-include is not working, since it is compiled into the DOM and makes the performance very bad.
After experimenting I figured out a solution, only working with a inline template. I am using a click handler to render the HTML with the detail-view directive to the DOM.
HTML
<div ng-controller="Ctrl">
{{item.name}} <button show-on-click item="item">Show Details</button>
<div class="detailView"></div>
<div ng-include="'include.html'"></div>
</div>
<!-- detailView Template -->
<script type="text/ng-template" id="detailView.html">
<p>With external template: <span>{{details.description}}</span></p>
</script>
Show On Click Directive
myApp.directive("showOnClick", ['$compile', '$parse', function($compile, $parse) {
return {
restrict: 'A',
scope: {
item: "=item"
},
link: function (scope, element, attrs) {
// Bind the click handler
element.bind('click', function() {
// Parse the item
var item = $parse(attrs.item)(scope);
// Find the element to include the details
var next = $(element).next('div.detailView');
// Include and Compile new html with directiv
next.replaceWith($compile('<detail-view details="item"></detail-view>')(scope));
});
}
};
}]);
Detail View Directive:
myApp.directive("detailView", ['$parse', '$templateCache', '$http', function($parse, $templateCache, $http) {
return {
restrict: 'E',
replace: true,
templateUrl: 'detailView.html', // this is not working
// template: "<div>With template in directive: <span>{{details.description}}</span></div>", // uncomment this line to make it work
link: function (scope, element, attrs) {
var item = $parse(attrs.details)(scope);
scope.$apply(function() {
scope.details = item.details;
});
}
};
}]);
Here is the full example on
Plunker
Is there a way to improve my solution, or what am I missing to load the external template?
Thanks beforehand!
You can also look at ng-if directive in Angular version 1.1.5 . ng-if would only render the html if condition is true. So this becomes
<div ng-controller="Ctrl">
{{item.name}} <button ng-if="showDetails" item="item" ng-click='showDetails=true'>Show Details</button>
<div class="detailView"></div>
<div ng-include="'include.html'"></div>
</div>
By just using ng-include:
<div ng-controller="Ctrl" ng-init="detailsViewTemplateSource='';">
{{item.name}}
<button ng-click="detailsViewTemplateSource = 'detailView.html'">
Show Details
</button>
<div ng-include="detailsViewTemplateSource"></div>
</div>
<!-- detailView Template -->
<script type="text/ng-template" id="detailView.html">
<p>With external template: <span>{{details.description}}</span></p>
</script>

Accessing properties of a child view created within {{#each}} iterator

Edit: Problem was with my own local settings and the way I was including the views in my application. Once I fixed those issues, the problem was resolves. The code here is actually correct. The answer Chrixian provided also work.
I am stuck on something that seems rather simple. I want to access some computed properties of my view constructed inside an each loop in handlebars.
<div class='build-buttons-wrapper'>
<button class="list-builds-button" {{action "toggleBuildsList" target="view"}} ></button>
<button class="build-button" {{action "buildApp" on="click" target="view"}} >Build</button>
</div>
<div class='builds-list'>
<h2 class="build-title">Latest builds</h2>
<ul class="builds-list">
{{#each content}}
{{#view Jimux.BuildView buildBinding="this"}}
<span class="build-date">{{createdAt}}</span>
<a {{bindAttr href="srcArchive"}} class="download-button source">Source</a>
{{! *here are different ways I have tried to access "finished" property* }}
{{log build.view.finished}}
{{log view.finished}}
{{log finished}}
{{log this.finished}}
{{log build.finished}}
{{#if build.finished}}
<div class="build-progressbar"></div>
{{else}}
<div class="build-progressbar"><div class="build-percent" style="width:{{unbound percent}}%"></div></div>
{{/if}}
{{/view}}
{{/each}}
</ul>
</div>
Here is the BuildsView which is using this template:
Jimux.BuildsView = Em.View.extend({
templateName: 'builds'
listVisible: false
classNames: ['builds-view']
buildApp: (view, event, ctx) ->
#get('controller').newBuild()
,
hideList: ->
#set 'listVisible', false
this.$(".builds-list").hide("slide", {direction: "up"}, 300)
,
showList: ->
#set 'listVisible', true
this.$(".builds-list").show("slide", {direction: "up"}, 300)
,
toggleBuildsList: (view, event, ctx) ->
if #get 'listVisible' then #hideList() else #showList()
,
didInsertElement: ->
#hideList() if not #get 'listVisible'
})
And here is the BuildView which is created inside the {{#each}} iterator in the template above.
Jimux.BuildView = Ember.View.extend(
tagName: 'div',
classNames: ['build-item'],
#testBinding: true,
sample: true,
finished: ( ->
return true
#return (#get 'percent') == 100
).property('percent')
)
Everything above works as expected. For example I can access percent property of each child view using {{percent}}. But if I define my own properties inside the Jimux.BuildView as show above, I cant seem to find a way to access them within the handlebars {{#each}} iterator. You can see the different ways I have tried inside the handlebars code with {{log}} statements, all those print undefined in the console. What am I missing here?
I'm assuming the percent property you are referring to is a property of each "content" object you are looping over-- if that's the case making finished look like this:
finished: (->
return #get('context.percent') is 100
).property('context.percent')
You should be able to simply use {{finished}} within the {{#view Jimux.BuildView}} .. {{/view}} block