I currently have a route servicerequests.index. In this route I am displaying a table of all service requests that I am getting via this call in my route:
model() {
return this.store.findAll('servicerequest').then(results =>
results.sortBy(this.get('selectedFilter')).reverse());
}
In my hbs file I have this power select:
{{#power-select options=filterOptions placeholder="Select a filter"
selected=selectedFilter onchange=(action (mut selectedFilter))
searchField="filterOptions" as |filter|}}
{{filter.descr}}
{{/power-select}}
In my controller I am defining the options:
filterOptions: [
{ descr: "created_at" },
{ descr: "priority" },
{ descr: "status" }],
actions: {
selectedFilter(filter) {
this.set('selectedFilter', filter);
}
},
What I want to happen is that when I select the different filter sort options to reorder the results on the page. How do you go about doing that?
With the data coming from the route and the options set in the controller I wasn't sure where to do the logic of the power selected.
Any thoughts or suggestions are appreciated.
Use a computer property in the controller for the sorting. Don't do it in the model hook.
My answer here is very related to this.
basically do this in your route:
model() {
return this.store.findAll('servicerequest');
}
and then in your controller:
filtetedModel: computed('selectedFilter', 'model.#each.{created_at,priority,status}', {
get() {
return this.model.sortBy(this.selectedFilter);
}
}),
filterOptions: [
{ descr: "created_at" },
{ descr: "priority" },
{ descr: "status" }
],
actions: {
selectedFilter(filter) {
this.set('selectedFilter', filter);
},
}
Related
I'm struggling a bit with the proper pattern to use here. I have a model which represents a power selector called selector, each selector has a hasMany with selectorOption which makes up the options for the selector
I then have a dashboardItem model which loops over each selector and implements it.
route.js
export default Route.extend({
model(params) {
return RSVP.hash({
dashboard: get(this, 'store').findRecord('dashboard', params.dashboard_id),
selectors: get(this, 'store').findAll('selector'),
});
},
setupController(controller, models) {
controller.setProperties(models);
},
});
template.hbs
{{#each selectors as |selector|}}
<div class="column is-12 object-item">
<div class="card">
<header class="card-header">
<p class="card-header-title">
{{selector.title}}
</p>
</header>
<div class="card-content">
{{#power-select-multiple
placeholder="Vision"
options=selector.selectorOptions
searchEnabled=false
onchange=(action 'something...') as |option|}}
{{option.title}}
{{/power-select-multiple}}
</div>
</div>
</div>
{{/each}}
I'm not sure what to do on the onchange, either with a custom function or using built in tools of power-select.
Each selector is a multi-selector.
This works correctly to the point that I can create any number of selectors and they display on the front end with their correct options as expected.
How should I go about saving the options the users choose against the dashboardItem?
Here is a section from the database which shows the models and their relationships. Note there is currently no relationship between a selector and a dashboardItem (Maybe there should be though?)
{
"selectorOptions" : {
"-Kyc7on207d_IxnNw2iO" : {
"title" : "Apple",
"vision" : "-Kyc7nG9Bz3aEGLked8x"
},
"-Kyc7qC9_uxFgXP9c7hT" : {
"title" : "Orange",
"vision" : "-Kyc7nG9Bz3aEGLked8x"
},
"-Kyc7qqZPMikoG1r3r5g" : {
"title" : "Bannana",
"vision" : "-Kyc7nG9Bz3aEGLked8x"
},
"-Kyc7uZu8MTfUdH70cBR" : {
"title" : "Blue",
"vision" : "-Kyc7rtTPTMJxAPacg-L"
},
"-Kyc7vJC3ImzVOEraALx" : {
"title" : "Green",
"vision" : "-Kyc7rtTPTMJxAPacg-L"
},
"-Kyc7wCrqDz8CD_I-dYy" : {
"title" : "Red",
"vision" : "-Kyc7rtTPTMJxAPacg-L"
}
},
"selectors" : {
"-Kyc7nG9Bz3aEGLked8x" : {
"title" : "Fruits",
"selectorOptions" : {
"-Kyc7on207d_IxnNw2iO" : true,
"-Kyc7qC9_uxFgXP9c7hT" : true,
"-Kyc7qqZPMikoG1r3r5g" : true
}
},
"-Kyc7rtTPTMJxAPacg-L" : {
"title" : "Colours ",
"selectorOptions" : {
"-Kyc7uZu8MTfUdH70cBR" : true,
"-Kyc7vJC3ImzVOEraALx" : true,
"-Kyc7wCrqDz8CD_I-dYy" : true
}
}
}
}
The solution was to not fight against relationships with basic array storage.
For example
Base
export default Model.extend({
title: attr('string'),
visionOptions: hasMany('vision-option'),
});
Bases Options
export default Model.extend({
title: attr('string'),
vision: belongsTo('vision'),
});
The model to save the selected objects on
export default Model.extend({
//...
visionOptions: hasMany('vision-option', {async: true}),
//...
});
The component to handle saving, and selecting the correct objects
export default Component.extend({
tagName: "",
classNames: "",
selectedVisions: computed('dashboardItem.visionOptions', function () {
const visionId = this.get('vision.id');
const options = this.get('dashboardItem.visionOptions');
return options.filterBy('vision.id', visionId);
}),
actions: {
addVision(newList) {
let dashboardItem = get(this, 'dashboardItem');
let options = get(this, 'selectedVisions');
options.forEach(function (me) {
if (!newList.includes(me)) {
dashboardItem.get('visionOptions').removeObject(me);
}
});
newList.forEach(function (me) {
if (!options.includes(me)) {
dashboardItem.get('visionOptions').pushObject(me);
}
});
dashboardItem.save().then(() => {
dashboardItem.notifyPropertyChange('visionOptions')
});
}
}
});
Template to render power-select
{{#power-select-multiple
placeholder=""
options=vision.visionOptions
searchEnabled=false
selected=selectedVisions
onchange=(action 'addVision') as |vision|}}
{{vision.title}}
{{/power-select-multiple}}
This allows there to be an unknown number of "visions", with an unknown number of "visionObjects" to be loaded and saved.
The notifyPropertyChange is required to update the computed property so the frontend renders when a user adds or removes a selected object. This is only awkward because there isn't a direct known database key.
i have two components in my template:
{{ property-pie-chart
models=model.hosts
defaultProp=""
filterByDate=filterByDate
chartData=[]
}}
{{ paged-filtered-list
data=model.hosts
dates=model.dates
page=page
pageSize=pageSize
filterByDate=filterByDate
pagerView=pagerView
initRouteAction=( action 'dateInit' )
dateFilterAction=( action 'filterByDate' )
termFilterAction=(action 'filterByTerm')
sortOrder=sortOrder
sortField=sortField
}}
I send action from paged-filtered-list component to controller, which triggers route transition with filterByDate as parameter:
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: [
'page',
'pageSize',
'sortField',
'sortOrder',
'filterByDate',
'filterByTerm'
],
filterByDate: "",
filterByTerm: "",
page: 1,
pageSize: 10,
pagerView: 4,
sortField: "",
sortOrder: 'asc',
lala: "",
actions: {
dateInit: function(sortedDates) {
if (!this.get('filterByDate')) {
let params = {
filterByDate: sortedDates.get('firstObject').get('key'),
page: this.get('page'),
pageSize: this.get('pageSize'),
pagerView: this.get('pagerView')
};
this.transitionToRoute('hosts', { queryParams: params});
}
},
filterByDate: function(value) {
if (value) {
let params = {
filterByDate: value,
page: 1,
pageSize: this.get('pageSize')
};
this.transitionToRoute('hosts', { queryParams: params});
}
},
filterByTerm: function(value) {
let params = {
filterByDate: this.get('filterByDate'),
page: 1,
pageSize: this.get('pageSize')
};
if (value) {
params['filterByTerm'] = value;
} else {
params['filterByTerm'] = "";
}
this.transitionToRoute('hosts', { queryParams: params});
}
}
});
Problem is that URL is updated and contains filterByDate, but first component property-pie-chart does not detect that filterByDate property is changed, altough i checked attributes in init/didUpdate methods and parameter is changed, can somebody help and explain what i am doing wrong?
Currently you are not setting filterByDate property in controller.
I would suggest the following approach,
You please declare the below property in corresponding route.js,
queryParams: { page: { refreshModel: true }, pageSize: { refreshModel: true },sortOrder: { refreshModel: true },filterByDate: { refreshModel: true },filterByTerm: { refreshModel: true }}
refreshModel denotes is whenever this property changed,then it will force to refresh the page.
and in controller.js, You don't need to call this.transitionToRoute('hosts', { queryParams: params}); instead you just set required queryParams participating property alone then transition will automatically taken care.
SideNote: It's good if you can change function name filterByTerm filterByDate by the way this is not related to problem
Update:
I am glad you sorted out the problem. but then I want to emphasize what are Computed Properties from ember guides.
In a nutshell, computed properties let you declare functions as properties. You create one by defining a computed property as a function, which Ember will automatically call when you ask for the property. You can then use it the same way you would any normal, static property.
https://guides.emberjs.com/v2.8.0/object-model/computed-properties/#toc_what-are-computed-properties
Generally, Ember HasMany relationship json format is follow,
{ "post" : { id:1, title:"this is title", comments:[1,2], writer: ...} }
But, i want to use next json format (because, my server return like this)
{ "post" : { id:1, title:"this is title",
comments:[
{id:1, bodytext:"blarblar...."},
{id:2, bodytext:"second blarblar...."},
], writer: ...} }
How can I use this?
Isn't there any problem in ember store relationship?
This is a job for EmbeddedRecordsMixin.
If you're implementing the server yourself and it's purpose-built for your ember application, you should consider switching to side-loading instead:
{ "post" : { id: 1,
title: "this is title",
comments: [1,2],
writer: ...
},
"comments": [ { id: 1,
bodytext: "blarblar...."
},
{ id: 2,
bodytext: "second blarblar...."
}
]
}
That way, it would be still just one request, but would work for more complicated structures (other than trees) as well.
Is this possible? I know I can do:
this.store.find('model', 1)
but that's not what I want. I would like to retrieve the json in this format: (working if I retrieve it in the route like this ):
App.OptionsRoute = Ember.Route.extend({
model: function () {
return {
"options":{
"id": "1",
"headline": "A Headline",
"results": [
{
"id": "1",
"title": 'Option 1',
},
{
"id": "2",
"title": "Option 2"
}
]
}
};
}
});
options model:
App.Options = DS.Model.extend({
headline: DS.attr(),
results: DS.attr()
});
options.hbs
<h5>{{options.headline}}</h5>
{{#each item in options.results}}
<h5>{{item.title}}</h5>
{{/each}}
I am using the RESTAdapter. And that is the only model that will be retrieved on that route. I would like to be able to use ember-data, but store.find expects an array.
You're missing a point here. First of all you're using bad format for your response. You need custom serializer. You can also use a bit more dirty workaround like this(but it works). Route:
App.OptionsRoute = Ember.Route.extend({
model: function() {
that = this;
return new Promise(function (resolve, reject) {
url = that.store.adapterFor('option').buildURL('option');
Ember.$.getJSON(url).then(function (json) {
body = json.options;
correct = {
options: [
body
]
};
that.store.pushPayload('option', correct);
resolve(that.store.all('option').get('firstObject'));
});
});
}
});
Template:
<h5>{{model.headline}}</h5>
{{#each item in model.results}}
<h5>{{item.title}}</h5>
{{/each}}
Application outputs:
A Headline
Option 1
Option 2
Working demo - please notice that I'm using $.mockjax to recreate your response from server, but it matches format you provided.
i have drop downlist in emberjs and i declare it like that below
{{view Ember.Select contentBinding="ResAdmin.adminController.serviceAreaList" selectionBinding="ResAdmin.adminController.serviceAreaSelection" optionLabelPath="content.ZipCode" optionValuePath="content.ServiceAreaID"}}
but i want to use kendo ui's dropdownlist which i can use like below
<input id="dropDownList" />
$(document).ready(function() {
$("#dropDownList").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: [
{ text: "Item1", value: "1" },
{ text: "Item2", value: "2" }
]
});
});
i want to use kendoui dropownlist with ember
Try it like wycats' examples for jqueryUI
App.KendoSelectView = Em.Select.extend({
didInsertElement: function () {
this.$().kendoDropDownList({
dataTextField: ....
});
}
});
You can probably pick up the attributes for the DDL from the select properties.