问题
What I'm having here is basically look like this:
filter
|_ todo
|_ todo
filter
|_ todo
filter
|_ todo
Several filterView which have todoView nested inside.
So first I'm creating instances of filterView and pass in all the params.
<ul id="todo-list">
{{view 'filter' control=controller.beforeFilter title="Before" }}
{{view 'filter' param='0' control=controller.todayFilter title="Today"}}
{{view 'filter' param='1' control=controller.tomorrowFilter title="Tomorrow" }}
</ul>
This is how it look like in filterView:
App.FilterView = Ember.View.extend({
classNames: ['filter-container'],
templateName: 'datefilter',
title: 'Today',
param: null,
control: null,
isHide: false,
click: function(){
this.toggleProperty('isHide');
}
});
and the corresponding template:
<div class="filter-bar">
<label class="filter-title">{{view.title}}</label>
<label class="filter-date">{{generateDate view.param}}</label> <!-- This is a handlebar's helper -->
<div class="filter-right-container">
<div class="filter-count">
<label> count </label> <!-- Show number of todos in this filter -->
</div>
</div>
</div>
<div class="filter-box" {{bind-attr class=view.isHide:hide}}>
{{#each todo in view.control}} <!-- So this will turn to in controller.someFunction -->
{{view 'todo'}}
{{/each}}
</div>
And this will be the TodoView
App.TodoView = Ember.View.extend({
templateName: 'todolist',
contentBinding: 'this',
classNames: ['todo-box']
})
And finally the controller
App.TodosController = Ember.ArrayController.extend({
beforeFilter: function(){
return this.get('model').filter(function(todo, index){
var date = todo.get('date');
if(moment(date).isBefore(moment(), 'days')){
return todo;
}
});
}.property('model.@each.date'),
todayFilter: function(){
return this.get('model').filter(function(todo, index){
var date = todo.get('date');
if(moment().isSame(date, 'days')){
return todo;
}
});
}.property('model.@each.date'),
tomorrowFilter: function(){
return this.get('model').filter(function(todo, index){
var date = todo.get('date');
if((moment().add(1, 'days')).isSame(date, 'days')){
return todo;
}
});
}.property('model.@each.date'),
});
So the TodoView will be created according to the return filtered record, but sometimes nothing will get returned. So the question is how to hide the filterView if no TodoView is created?
Is there something like
{{#each todo in view.control}}
{{view 'todo'}}
{{else}}
{{'Set filterView isVisible to false'}}
{{/each}}
or I could easily get this done using collectionView? but how?
Really appreciate to any help
回答1:
Here is complete solution.
To sum it up :
- An ArrayController to hold all your events
- Each event holds a date
- Header elements hold a date with truncated hours and a boolean for display
In your template, simply iterate over your array and display the header as you like (this
is my controller context):
{{#each randDate in this}}
<div {{bind-attr class=":border-row randDate.isHeader:header"}}>{{formatDate randDate.date isHeader=randDate.isHeader}}</div>
{{/each}}
To differenciate whether there is a date following or not, an easy choice would be to put all your events objects into a [LinkedList][2]
data structure and not just a simple Array
. This way, each event knows the one after himself and knows if it should be displayed. There are tons of implementations of this kind of list, so just pick one where an element knows its next element (the Doubly for instance, but maybe its not the best suited for your case). Then, you could do something like that (this is pseudo code) :
// inside the each loop
{{#if randDate.isHeader && randDate.next.isHeader}} // not sure this && operator is supported by handlebars at the moment
// here you have 2 headers one after the other, do nothing
{{else}}
// one of the 2 is not a header, display your header/event as usual
{{/if}}
Does it help ?
回答2:
So what I did is instead of return directly from the controller, I check the length and save it in another variable:
beforeFilter: function(){
var data = this.get('model').filter(function(todo, index)
{
var date = todo.get('date');
if(moment(date).isBefore(moment(), 'days')){
return todo;
}
});
this.set('beforeCount', data.length);
return data;
}.property('model.@each.date')
When creating new instance of view, I'll pass one more param in (the controller.variable which save the length):
{{view 'filter' control=controller.beforeFilter countControl=controller.beforeCount title="Before" }}
And in the view, we can first check the length, and if theres nothing, we will hide the header:
dataChanged: function(){
var count = this.get('countControl'); //<-- this will get the length of the return data
if(count<1){
this.set('isVisible', false);
}
}.observes('countControl').on('didInsertElement')
来源:https://stackoverflow.com/questions/27439062/ember-js-hiding-a-view-if-no-childview-is-created