I have a set of json data I get from server, what I need is to sort them before I show to screen.
Data Example:
{
"statuses": [
{
"id": 1,
"title":"Post title 1",
"date":"2014-12-20T11:30:48+0000",
"sticky":true,
"comments":[]
},
{
"id": 2,
"title":"Post title 2",
"date":"2014-12-25T11:30:48+0000",
"sticky":false,
"comments":[]
},
{
"id": 3,
"title":"Post title 3",
"date":"2014-12-15T11:30:48+0000",
"sticky":true,
"comments":[]
},
{
"id": 4,
"title":"Post title 4",
"date":"2014-12-10T11:30:48+0000",
"sticky":false,
"comments":[]
}
]
}
I need to
Show sticky statuses first sticky: true sort by date descending.
After then show normal statuses sticky: false sort by date descending
So far I was just able to list them in given data order. You can see the example here http://jsfiddle.net/sisir/kqxz71sg/2/
Resolved
Final working version is given in jsfiddle, I am also adding it here in case the jsfiddle link becomes obsolete in future.
HTML
<div id="main"></div>
<script type="text/x-handlebars" data-template-name="index">
{{input type="text" value=title}}
<button {{action "addStatus"}}>Submit</button>
{{#each status in sortedStatuses}}
<p {{bind-attr class="status.sticky:sticky"}}>{{status.title}}</p>
{{/each}}
</script>
JS
App = Ember.Application.create({
rootElement: '#main'
});
App.ApplicationAdapter = DS.FixtureAdapter;
App.Store = DS.Store.extend();
var attr = DS.attr(),
string = DS.attr('string'),
boolean = DS.attr('boolean'),
number = DS.attr('number'),
hasMany = DS.hasMany(),
date = DS.attr('date', {
defaultValue: function() { return new Date(); }
});
App.Status = DS.Model.extend({
sticky: boolean,
title: string,
date: date,
comments: attr
});
App.Status.reopenClass({
FIXTURES: [
{
"id": 1,
"title":"Post title 1",
"date":"2014-12-20T11:30:48+0000",
"sticky":true,
"comments":[]
},
{
"id": 2,
"title":"Post title 2",
"date":"2014-12-25T11:30:48+0000",
"sticky":false,
"comments":[]
},
{
"id": 3,
"title":"Post title 3",
"date":"2014-12-15T11:30:48+0000",
"sticky":true,
"comments":[]
},
{
"id": 4,
"title":"Post title 4",
"date":"2014-12-10T11:30:48+0000",
"sticky":false,
"comments":[]
}
]
});
App.IndexRoute = Ember.Route.extend({
setupController: function(controller){
var statuses = this.store.find('status');
controller.set('statuses', statuses);
}
});
App.IndexController = Ember.Controller.extend({
sortedStatuses: function(){
var statuses = this.get('statuses');
var stickyStatuses = statuses.filterBy('sticky').sortBy('date').reverse();
var nonStickyStatuses = statuses.filterBy('sticky', false).sortBy('date').reverse();
var sortedStatuses = stickyStatuses;
sortedStatuses.pushObjects(nonStickyStatuses);
return sortedStatuses;
}.property('statuses.#each'),
actions: {
addStatus: function(){
console.log('ok');
var status = {
title: this.title,
date: new Date(),
sticky: true
}
var status = this.store.createRecord('status', status);
status.save();
}
}
});
css
.sticky{
background: yellow;
}
Create a new computed property called sortedStatuses as follows:
App.IndexController = Ember.Controller.extend({
sortedStatuses: function(){
var statuses = this.get('statuses');
var stickyStatuses = statuses.filterBy('sticky').sortBy('date').reverse();
var nonStickyStatuses = statuses.filterBy('sticky', false).sortBy('date').reverse();
var sortedStatuses = stickyStatuses;
sortedStatuses.pushObjects(nonStickyStatuses);
return sortedStatuses;
}.property('statuses.#each')
});
In your template, you can then loop over sortedStatuses
{{#each status in sortedStatuses}}
<p {{bind-attr class="status.sticky:sticky"}}>{{status.title}}</p>
{{/each}}
Working example here
Related
I have a router that returns data from the data model.
I want to use this data to bind it to a widget in a view.
Model:
myApp.Unit = DS.Model.extend({
active: DS.attr('boolean'),
allowdecimals: DS.attr('boolean'),
name: DS.attr('string'),
count: DS.attr('number'),
});
Router:
myApp.EunitsRoute = Ember.Route.extend({
model: function() {
return this.store.find('unit');
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set('units', model);
},
actions: { ...
In the view I expect an object formated as follows:
[ {"id": 1,"active": true,"allowdecimals": true,"name": "Pint","count": 8},
{"id": 2,"active": true,"allowdecimals": true,"name": "Each","count": 8},
...]
What I am getting now in the view is an object:<DS.RecordArray:ember400>
View:
var source10 = {
datatype: "array",
datafields: [
{ name: 'id' },
{ name: 'name' },
{ name: 'allowdecimals' },
{ name: 'active' },
{ name: 'count' }
],
localdata: controller.get('units')
};
var dataAdapter10 = new $.jqx.dataAdapter(source10);
$("#eunits_grid").jqxGrid({
pageable: true,
theme: 'energyblue',
autorowheight : true,
rowsheight : 50,
pagesize: 10,
source: dataAdapter10,
....
Template:
<script type="text/x-handlebars" data-template-name="eunits">
<div class="col-md-12">
<h3 class="page-header">Edit Units</h3>
{{#if adding}}
{{view AddnewunitView}}
{{/if}}
{{view UnitsView id='eunits_grid'}}
</div>
</script>
I am new to ember.. I have 2 models..
Music.Artist = DS.Model.extend({
name: DS.attr('string'),
dob : DS.attr('date'),
songs : DS.hasMany('song',{async:true})
});
Music.Artist.FIXTURES=[
{
id:1,
name:'John',
dob:new Date(),
songs:['1','2']
},
{
id:2,
name:'Robbin',
dob:new Date(),
songs:['1','2']
}
];
Music.Song = DS.Model.extend({
title:DS.attr('string'),
artists:DS.hasMany('artist',{async:true})
});
Music.Song.FIXTURES = [
{
id:1,
title:'A day to remember',
artists:[1,2]
},
{
id:2,
title:'Cant live without you',
artists:[1,2]
}
];
I want for url "/songs/id"... I get all the songs that has an artist with the given id.
Music.Router.map(function(){
this.resource('songs',{path:'/songs/:id'});
});
Music.SongsRoute = Ember.Route.extend({
model:function(param){
var artist = this.store.find('artist',param.id);
return artist.get('songs');
}
});
But it returns undefined... How to get the list of songs that are related to the Artist.
Is there any way i can achieve this by using only routes.
How to read the array of songs, if not through get.
Based on the current versions of Ember (1.6.1) and Ember-Data (1.0.0-beta.9), here's how I got your example working. I changed your route naming, I think you really want something like /artists/:artist_id which will list the artist's data, including all his songs.
Your Artist and Song model declarations seem fine, but I declared the fixtures like so:
Music.Artist.reopenClass({
FIXTURES: [
{
id:1,
name:'John',
dob:new Date(),
songs:['1','2']
},
{
id:2,
name:'Robbin',
dob:new Date(),
songs:['1','2']
}
]
});
Music.Song.reopenClass({
FIXTURES: [
{
id:1,
title:'A day to remember',
artists:[1,2]
},
{
id:2,
title:'Cant live without you',
artists:[1,2]
}
]
});
For the router:
Music.Router.map(function() {
this.resource('artists');
this.resource('artist', { path: '/artists/:artist_id' });
});
For the routes:
var Music.ArtistsRoute = Ember.Route.extend({
model: function() {
return this.store.find('artist');
}
});
var Music.ArtistRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('artist', params["artist_id"]);
}
});
For your templates:
// artists.hbs
<ul>
{{#each}}
<li>{{#link-to 'artist' this}}{{name}}{{/link-to}}</li>
{{/each}}
</ul>
// artist.hbs
<h1>{{name}}</h1>
<hr>
<h2>Songs</h2>
<ul>
{{#each songs}}
<li>{{title}}</li>
{{/each}}
</ul>
Hope this helps!
Here is the thing I have a form which have multiple checkboxes and they have the same name attribute "classifications[]"
with the code:
<input type="checkbox" name="classification[]" value="Value 1" />
<input type="checkbox" name="classification[]" value="Value 2" />
<input type="checkbox" name="classification[]" value="Value 3" />
this works properly by default it posts "classification[]" like this
[ 0 => "Value 1", 1 => "Value 2"]
but I want this to work in an ember app so I did this (shortened version)
// index.html
{{input type="checkbox" name="classification[]" value="Cell Member" checked=classification}}
App.ApplicationController = Ember.Controller.extend({
var user = this.store.createRecord('user',{
classification: this.get("classification")
})
user.save();
})
App.User = DS.Model.extend({
classification: DS.attr("string")
});
but the only posted classification value is True..
try this
// index.html
{{#for possibleValues}}
<label>{{this.label}}</label>
{{input type="checkbox" value=this.isChecked}}
{{/for}}
<a {{action save}}>save</a>
var possibleValue = [{
label: 'Label for value 1',
isChecked: false,
value: 'Value 1'
},{
label: 'Label for value 2',
isChecked: false,
value: 'Value 2'
},{
label: 'Label for value 3',
isChecked: false,
value: 'Value 3'
}];
App = Ember.Application.create();
App.ApplicationAdapter = DS.RESTAdapter.extend();
App.ApplicationController = Ember.ObjectController.extend({
init: function () {
this._super();
var user = this.store.createRecord('user');
this.set('content', user);
},
actions:{
save: function () {
var user = this.get('content'),
collected = user.get('classifications');
this.set('collected', collected);
user.save();
}
},
//executes when isChecked is changed in one item of possibleValues
collectChecked: function () {
var classifications;
classifications = this.get('possibleValues').filterBy('isChecked', true); //filter checked only
classifications = classifications.mapBy('value'); //map values
this.set('classifications', classifications);
console.log(classifications);
}.observes('possibleValues.#each.isChecked'),
possibleValues: possibleValues
});
App.RawTransform = DS.Transform.extend({
deserialize: function(serialized) {
return serialized;
},
serialize: function(deserialized) {
return deserialized;
}
});
App.User = DS.Model.extend({
classifications: DS.attr('raw')
});
http://jsbin.com/dokiwati/6/edit
I'm using a Multiselect view:
{{view Ember.Select
multiple="true"
contentBinding="App.filtersProductController"
selectionBinding="App.filtersController.products"
optionLabelPath="content.fullName"
optionValuePath="content.id"
isVisibleBinding="App.filtersController.productListBox"}}
Is it possible to preselect multiple values in the "select" box and to change the selected values programmatically? Background: I want to save different combinations of three "select" boxes settings as bookmarks. When loading a bookmark, I have to set the "select" boxes values.
Thank you
Yes. In your controller you have to create a property to keep the selected value or values when working with Ember.Select.
In the code below I'm setting the Greetings as the content of the select box, in the controller that lists those Greetings (check ApplicationRoute), I also have a property called selectedItems which I'm binding to the Select and I'm using a couple other properties to filter the values I want to pre-select (1 and 3) in case none of the items are already selected when the view loads.
This will render a multiple select box with the items which the id are either 1 or 3 marked as selected. You can see the source here: http://jsfiddle.net/schawaska/Y8P4m/
Handlebars:
<script type="text/x-handlebars">
<h1>Test</h1>
{{view Ember.Select
multiple="true"
selectionBinding="controller.selectedItems"
contentBinding="controller"
optionLabelPath="content.text"
optionValuePath="content.id"}}
</script>
JavaScript:
window.App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
});
App.Greeting = DS.Model.extend({
text: DS.attr('string'),
when: DS.attr('date'),
selected: false,
isSelected: function() {
return this.get('selected');
}.property('selected')
});
App.ApplicationController = Em.ArrayController.extend({
preselected: function() {
return this.get('content').filter(function(greeting) {
return greeting.get('id') == 1 ||
greeting.get('id') == 3;
});
}.property('content.#each'),
selectedItems: function() {
if(this.get('selected.length') <= 0) {
return this.get('preselected');
} else {
return this.get('selected');
}
}.property('selected', 'preselected'),
selected: function() {
return this.get('content').filter(function(greeting) {
return greeting.get('isSelected');
})
}.property('content.#each')
});
App.Greeting.FIXTURES = [
{id: 1, text: 'First', when: '3/4/2013 2:44:52 PM'},
{id: 2, text: 'Second', when: '3/4/2013 2:44:52 PM'},
{id: 3, text: 'Third', when: '3/4/2013 2:44:52 PM'},
{id: 4, text: 'Fourth', when: '3/4/2013 3:44:52 PM'}
];
App.ApplicationRoute = Em.Route.extend({
setupController: function(controller) {
controller.set('model', App.Greeting.find());
}
});
I have created a complete example with single and multi "select" elements. You can set defaults and change the selected value programmatically or by using the "select" GUI element. The controller code:
// class for single selects
App.SingleSelectFilterController = Ember.ArrayController.extend({
selection: null,
active: true,
update: function(id) {
this.set("selection", id);
},
getSelectedId: function() {
return this.get("selection");
}
});
// class for multi selects
App.MultiSelectFilterController = Ember.ArrayController.extend({
selection: null,
active: true,
update: function(selectionIds) {
// Workaround: Reinitializing "content". How to do it well?
var contentCopy = [];
for(i = 0; i < this.get("content").length; i++) {
contentCopy.push(this.get("content")[i]);
}
this.set("content", contentCopy);
this.set("selection", selectionIds);
},
selected: function() {
var me = this;
return this.get('content').filter(function(item) {
for(i = 0; i < me.get("selection").length; i++) {
if(me.get("selection")[i] === item.get('id')) { return true; }
}
return false;
});
}.property('content.#each'),
getSelectedIds: function() {
var ids = [];
for(i = 0; i < this.get("selected").length; i++) {
ids.push(this.get("selected")[i].get("id"));
}
return ids;
}
});
// create single and multi select controllers
App.metricController = App.SingleSelectFilterController.create();
App.metricController.set("content", App.filterData.get("metrics"));
App.metricController.set("selection", "views"); // set default value for single select element
App.platformController = App.MultiSelectFilterController.create();
App.platformController.set("content", App.filterData.get("platforms"));
App.platformController.set("selection", ["plat-black"]); // set default value for multi select element
And the complete example:
http://jsfiddle.net/7R7tb/2/
Thanks to MilkyWayJoe for his help!
Perhaps somebody knows how to fix the workaround (see the code comment above)?
I'm trying to make an image slideshow with next/previous buttons but I don't understand how I should make it work all together. Can someone help me glue the pieces?
This is how the data looks like:
{
"newsitems": [
{
"id": "1",
"title": "Amai het wordt bangelijk!",
"mediaitems": [
{
"id": "AEOpX8tmiUI",
"newsitem_id": "1",
"value": "AEOpX8tmiUI"
},
{
"id": "kxopViU98Xo",
"newsitem_id": "1",
"value": "kxopViU98Xo"
},
{
"id": "1",
"newsitem_id": "1",
"value": "1276468632.JPG"
},
{
"id": "3",
"newsitem_id": "1",
"value": "1278286227.jpg"
}
]
}
]
}
I'd like to let the user iterate the mediaitems array. So when the user enters a route:
http://domain.com/#!/newsitems/1/overlay/kxopViU98Xo
That item should be in the center of the screen and a next/prev button should take the user to the next or previous item in the array.
This is how my route looks like:
App.MediaitemRoute = Ember.Route.extend({
model: function(params) {
return App.Mediaitem.find(params.mediaitem_id);
},
setupController: function(controller, model) {
this.controllerFor('overlay').set('content', model);
},
renderTemplate: function(controller, model) {
this.render('overlay', { into: 'application', outlet: 'overlay', controller: 'overlay'});
}
});
And this is the ObjectController for the overlay:
App.OverlayController = Ember.ObjectController.extend({
prev: function(){
var mediaitems = this.get('model').get('newsitem.mediaitems');
var currentMediaItemID = this.get('model').get('id');
var currentIndex = 0;
var i = 0;
mediaitems.forEach(function(object){
if(object.get('id') == currentMediaItemID) currentIndex = i;
i++;
});
// How should I transition to the next object?
}
});
The route renders a template called "overlay' which has two actions: "prev" and "next" (I'm only showing prev in my controller to keep things clean).
My two concerns are: the code to lookup the currentitem in the array (and code to get the next or previous object) just feels 'wrong' or overly 'complex'.
I don't know how to update the route and redirect to the next/previous item.
Some more useful stuff:
Handlebars template:
<script type="text/x-handlebars" data-template-name="overlay">
<div class="overlay">
<a {{action "prev" target="controller"}}>PREV</a>
<a {{action "next" target="controller"}}>NEXT</a>
</div>
</script>
My models:
App.Newsitem = DS.Model.extend({
title: DS.attr('string'),
mediaitems: DS.hasMany('App.Mediaitem')
});
App.Mediaitem = DS.Model.extend({
value: DS.attr('string'),
newsitem: DS.belongsTo('App.Newsitem')
});
My routes:
App.Router.map(function(){
this.resource('newsitems', function(){
this.resource('newsitem', {path:':newsitem_id'}, function(){
this.resource('mediaitem', {path:'/overlay/:mediaitem_id'});
});
});
});