Ember save component value (normal saving is no prob) - ember.js

I am struggeling to get a gridster layout values saved in my model: normal saving isn't that big deal.. just the grid layout.. how to fix this part?
Component: Serialized data availible after resized grid
export default Ember.Component.extend({
tagname: "",
Setupgridster: function(){
Ember.$(".gridster ul").gridster({
widget_base_dimensions: [359, 232],
widget_margins: [5, 5],
testvalue: 213213,
helper: 'clone',
resize: {
enabled: true,
max_size: [3, 3],
min_size: [1, 1],
stop: function (e, ui, $widget) {
var widget_base_dimensions = this.serialize($widget)[0];
}
},
serialize_params: function($w, wgd) {
return {
col: wgd.col,
row: wgd.row,
size_x: wgd.size_x,
size_y: wgd.size_y
};
}
}).data('gridster');
}.on("didInsertElement")
});
Save controller
export default Ember.Controller.extend({
model: 'layout',
actions: {
save: function(){
var newName= this.store.createRecord('layout', {
title: this.get('title'),
/** Don't know how to get in here serialized gridster data **/
layout: this.get('gridsterdata')
});
newName.save();
alert('saved');
this.transitionToRoute('index');
}
});
Someone told me to intergrate the save option into the component itself as an action, but I haven't got a clue how to make this work. Could somebody fix this or make a suggestion. I should be really pleased! (looking allready 1 week on this issue)

so you found the gridster resize stop callback, all you should need to do is:
export default Ember.Component.extend({
tagname: "",
Setupgridster: function(){
var _this = this;
Ember.$(".gridster ul").gridster({
...
resize: {
stop: function (e, ui, $widget) {
_this.sendAction('save', your_params_here);
var widget_base_dimensions = this.serialize($widget)[0];
}
}
}).data('gridster');
}.on("didInsertElement")
});
and then in your template where you are using your component, bind the action:
{{gridster-component save='save'}}
and modify your controller save action to take whatever arguments you send from the component.

Related

Calling Ember Model in Computed Property returns incorrect array

I'm trying to format data held in an Ember Model so that I can plug it into a Chart Component.
Route code:
import Route from '#ember/routing/route';
export default Route.extend({
model() {
let dateFrom = this.paramsFor('dashboard').dateFrom
let dateTo = this.paramsFor('dashboard').dateTo
let hash = {dateFrom, dateTo}
return Ember.RSVP.hash({
custakelist: this.get('store').query('custakelist', hash),
barchart: this.get('store').query('barchart', hash),
});
},
setupController(controller, models) {
this._super(controller, models);
controller.set('barchart', models.barchart);
controller.set('custakelist', models.custakelist);
},
Controller Code:
import Controller from '#ember/controller';
import groupBy from 'ember-group-by';
export default Controller.extend({
entriesByDate: groupBy('custakelist', 'take_list_date'),
entriesByAge: groupBy('custakelist', 'patient_age'),
wardData: Ember.computed.map('entriesByDate', function(group) {
return {
label: group.value,
count: group.items.length
};
}),
ageData: Ember.computed.map('entriesByAge', function(group) {
return {
label: group.value,
count: group.items.length
};
}),
clerkData: Ember.computed.map('barchart', function(barchart) {
return {
label: barchart.label,
count: barchart.count
};
}),
});
I know that the models are being loaded on the page correctly thanks to Ember Data. I also know that the 'custakelist' model is being used by other charts.
When I try to use the model 'barchart' and log the result to the console I can see that an array with the correct number of items is created but they don't contain any values, they just display as follows:
0: {label: Computed Property, count: Computed Property}
How can I make the data that is already loaded as per my model usable in this context?
I solved this by iterating on the model with a forEach and putting the result in a new array ready to plug into my chart:
clerkData: Ember.computed('barchart', function(test) {
let newArray = []
this.get('barchart').forEach(function(x) {
let newLabel = moment(x.data.label).format("MMM Do YY")
let newCount = x.data.count
let newData = {label:newLabel, count:newCount}
newArray.push(newData)
})
return newArray
}),

Ember JS: Highcharts.js into a component

Updated 03/17/2016 to better reflect current best practices for EmberJS v1.13.0 and up.
Problem
I am rendering Highcharts into a component and i almost have it working, but the binding of a property into the component is getting lost somewhere.
This is how I call the component:
//templates/index.hbs
{{pie-chart data=pieData}}
This is what the data property looks like (currently set in a controller):
//controllers/index.js
import Ember from 'ember';
export default Ember.Controller.extend({
init() {
this._super(...arguments);
this.pieData = [
['0 - 30', 2.5],
['31 - 60', 7.5],
['61 - 90', 12.5],
['91 - 120', 77.5]
];
}
});
And here is the component logic:
//components/pie-chart.js
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['chart'],
renderChart() {
return this.$().highcharts({
chart: {
height: 275
},
title: null,
plotOptions: {
pie: {
dataLabels: {
enabled: false
}
}
},
series: {
type: 'pie',
data: this.get('data')
},
colors: ['#777777', '#888888', '#999999', '#aaaaaa', '#bbbbbb', '#cccccc', '#dddddd', '#eeeeee'],
credits: {
enabled: true
}
});
},
didUpdateAttrs() {
let chart = this.$().highcharts();
let series = this.get('data');
chart.series[0].setData(series);
},
didInsertElement() {
this._super(...arguments);
this.renderChart();
},
willDestroyElement() {
this.$().highcharts().destroy();
}
});
i got the idea from this blog and i am trying to adapt it to make more charts.
the chart renders onto the screen, but it is blank... there are no errors to report... the only thing i can think is the data property is not being handled correctly in order to plot the graph?
I am not sure if this is my wrong use of Ember code, or wrong use of Highcharts code?
Solution
the series property inside the highchart was supposed to be an array of objects.. but I mistakenly defined just an object:
the fix:
series: [{
type: 'pie',
data: this.get('data')
}],
So, that is how you render a Highchart.js into a component :)

Ember: use controller data in route or how to fetch data properly

This question is a follow up on my previous question: Architecture for reusable object in ember
In my app I create multiple charts using an Ember.Component. The daterange for all the charts is controlled by a Daterangepicker which has its own controller etc.. Now the data for each chart is fetched in the IndexRoute (with an ajax call), and the daterange is passed in the query string.
The problem is that I can't seem to figure out how to access the daterange from the IndexRoute. Here's my code:
IndexRoute.js
App.IndexRoute = Ember.Route.extend({
model: function(){
var that = this;
return Ember.Object.extend({
registrationsData: null,
registrations: function() {
var self = this;
$.ajax({
url: Routing.generate('ysu_user_api_statistics_registrations', {startDate: that.dateRange.startDate, endDate: that.dateRange.endDate}),
success: function(data) {
var labels = [];
var values = [];
var chartData = {
labels : data.labels,
datasets : [
{
data : data.values,
}
],
};
self.set('registrationsData', chartData);
}
});
}.property(),
}).create();
},
dateRange: Ember.Object.create({
id: 1,
startDate: '2013-08-01',
endDate: '2013-08-31'
}),
});
Index.hbs
{{ my-chart title="Registrations" dataBinding=model.registrations registrationsDataBinding=model.registrationsData}}
MyChartComponent.js
App.MyChartComponent = Ember.Component.extend({
...
dataBinding: null,
registrationsDataBinding: null,
dateRangeBinding: null,
modelDateRangeBinding: null,
chartContext: null,
myChartController: null,
didInsertElement: function() {
/* Create and set controller */
if (!this.get('myChartController')) {
myChartController = new App.MyChartController()
this.set('myChartController', myChartController);
}
this.set('chartContext', $(this.get('element')).find('canvas')[0].getContext("2d"));
},
drawChart: function() {
if(this.get('chartContext')) {
var ctx = this.get('chartContext');
var options = {
bezierCurve : false,
pointDotRadius : 6,
pointDotStrokeWidth : 4,
datasetStrokeWidth : 4,
}
var myNewChart = new Chart(ctx).Line(this.get('registrationsDataBinding'), options);
}
}.observes('registrationsDataBinding', 'myChartController.dateRange'),
});
MyChartController.js
App.MyChartController = Ember.ArrayController.extend({
container: App.__container__,
needs: ['daterangepicker'],
dateRange: 'controllers.daterangepicker.selectedRange',
dateRangeBinding: 'controllers.daterangepicker.selectedRange',
});
I must admit, this setup feels kinda weird. So ultimately my question is:
What would be the correct way to fetch data for my charts based on startDate and endDate set in my DatePickerController?
I have been struggling with this problem as well.
In some of my apps, I've needed the URL to control the date range (e.g. a particular month). In these cases, I would created a MonthRoute and a MonthModel - think of it as a monthly report. The MonthModel has a hasMany property of the actual data I wanted to chart:
App.Month = DS.Model.extend({
companies: DS.hasMany('App.Company')
});
A datepicker would let the user enter a new route, which would fetch (say) the Jan-2013 month model
{
month: {
id: 'Jan-2013',
companies: [
{name: 'Acme, Inc', revenue: 10425, ...},
...
]
}
}
Then, I would set the embedded companies data on my CompaniesController in the setupController hook:
App.MonthRoute = Ember.Route.extend({
setupController: function(controller, model) {
controller.set('model', model);
this.controllerFor('companies').set('model', model.get('companies'));
}
});
Then, I would do the various array manipulations on my CompaniesController, and make that data available to my charts.
I have some code for this up on github, as well as a demo. I'd be interested to hear your thoughts.

Run jquery at the end of Ember.CollectionView rendering

I have a ContainerView which contains a CollectionView. After this CollectionView renders on the screen I need to perform a jquery function which essentially looks through the content of the rendered template and performs some display modifications.
If I perform that jquery within the didInsertElement of CollectionView it works but it gets executed for every single element in the CollectionView where as I really just need it to be done once at the end. How do I specify that?
http://jsfiddle.net/JFqNr/ (note doesn't render on jsfiddle or some reason but just to show you structure)
App = Ember.Application.create();
App.FooContainerView = Ember.ContainerView.extend({
childViews: ['elementList'],
elementList: Ember.CollectionView.extend({
content: function() {
return [
{ Title: "Dashboard", ID: "dashboard" },
{ Title: "Invoices", ID: "invoices" },
{ Title: "Expenses", ID: "expenses" },
{ Title: "People", ID: "people" },
{ Title: "Reports", ID: "reports" },
{ Title: "Settings", ID: "settings" }
];
}.property(),
template: Ember.Handlebars.compile( '{{view.content.title}}' ),
didInsertElement: function() {
// perform jquery function
}
}),
didInsertElement: function() {
// does not work if perforemed here
}
});
App.initialize();
​
The functionality to do this has only very recently been added to the master branch, so you will need to be compile your own version of Ember.
You can now schedule into an afterRender queue to run after all the individual views have been rendered.
App.FooContainerView = Ember.ContainerView.extend({
// Existing code
didInsertElement: function() {
Ember.run.scheduleOnce('afterRender', this, function(){
// perform jQuery function here;
});
}
See https://github.com/emberjs/ember.js/pull/1528 for code details.

How to manipulate a list item from it's view in emberjs

I have an Ember application with both a view and a controller:
http://jsfiddle.net/gavriguy/EDr4G/
I want to mark the current item the user clicks as read - by changing it's related model.
I'm currently able to do that by figuring the item's index of the view - but the problem is that i can't be sure that the index on the view is the same as the index on its controller.
Any thoughts?
JavaScript:
App.tempController = Em.ArrayController.create({
content: [
{
title: 'A',
unread: true},
{
title: 'B',
unread: true},
{
title: 'C',
unread: false}
]
});
App.someItemsView = Ember.CollectionView.create({
contentBinding: 'App.tempController.content',
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile('<div>{{content.title}} unread: {{content.unread}}</div>'),
click: function(event) {
//How to mark current clicked item as read?
console.log(this.content);
console.log(event);
this.set('content.unread', false);
}
})
});​
Inside your click handler you can get the reference to the array item for which the view is rendered via this.get('content'). So you can set the flag via this.setPath('content.unread', false), see http://jsfiddle.net/pangratz666/t6Nst/:
itemViewClass: Ember.View.extend({
template: Ember.Handlebars.compile('<div>{{content.title}} unread: {{content.unread}}</div>'),
click: function(event) {
// this.content is the item in the array on which this click event occures.
this.setPath('content.unread', false);
}
})