Delete a key (and value) from ember object - ember.js

Ember newbie and I have a feeling I am doing something very wrong here. Basically, I am trying to use an action to delete a key from a custom ember object. The action takes the key as the parameter (though that's a very jquery way to do it - perhaps I am missing a more "ember" way to do it?)
I created a twiddle
I am able to set the value to null which kind of works, but I'd prefer to remove the key and the value entirely. I would think .removeObject(key) would be the ticket, but it doesn't work. The console complains with:
Uncaught TypeError: thisData.removeObject is not a function
So I think I am using it in the wrong context.
Here's my example controller:
import Ember from 'ember';
const UrlObj = Ember.Object.extend({});
export default Ember.Controller.extend({
urlData: UrlObj.create({
queryParams: {
filter_breadcrumb: [
'Jewelry > Rings',
'Clothing and Accessories > Sweaters'
],
filter_price: ['100.0-200.0'],
filter_size: ['S','L'],
paging: 18,
q: 'gold',
search_sort: 'relevance'
}
}),
actions: {
deleteStuff(key) {
alert("deleteStuff called with " + key);
let thisData = Ember.get(this.urlData, 'queryParams');
//thisData.removeObject(key); // doesn't work, wrong context?
//Ember.get(this.urlData, 'queryParams').removeObject(key); // doesn't work, wrong context?
//delete thisData[key]; // this deletes it from the object but it's JS so ember is not aware of it
Ember.set(thisData, key, null); // this kind of works, but I'd like to remove the key AND the value
}
}
});
I commented out the lines that don't work.
Here's my template:
here's the data list:<br>
{{#each-in urlData.queryParams as |key value|}}
<a href="#" {{action "deleteStuff" key}}>{{key}}: {{value}}</a><br>
{{/each-in}}
Any help appreciated!

You need to notify property changed.
And no need to use Ember.Object
export default Ember.Controller.extend({
urlData: {
queryParams: {
filter_breadcrumb: [
'Jewelry > Rings',
'Clothing and Accessories > Sweaters'
],
filter_price: ['100.0-200.0'],
filter_size: ['S','L'],
paging: 18,
q: 'gold',
search_sort: 'relevance'
}
},
actions: {
deleteStuff(key) {
alert("deleteStuff called with " + key);
let thisData = Ember.get(this.urlData, 'queryParams');
delete thisData[key];
this.notifyPropertyChange('urlData');
}
}
});

No need to use "notifyPropertyChange"
export default Ember.Controller.extend({
urlData: {
queryParams: {
filter_breadcrumb: [
'Jewelry > Rings',
'Clothing and Accessories > Sweaters'
],
filter_price: ['100.0-200.0'],
filter_size: ['S','L'],
paging: 18,`enter code here`
q: 'gold',
search_sort: 'relevance'
}
},
actions: {
deleteStuff(key) {
alert("deleteStuff called with " + key);
let thisData = this.get('urlData').queryParams;
delete thisData[key];
console.log(this.get('urlData')); //u ll get deleted data
}
}
});

Related

Use Mixin property in a Controller

This is a crappy example, but I am merely trying to use a mixin's property in a controller. I did the same thing in a route and could access that property. I've tried every way to reference a property I know... What am I misunderstanding?
// app/mixins/author-data.js
import Ember from 'ember';
export default Ember.Mixin.create({
authorName: 'Example author name',
});
// app/controllers/application.js
import Ember from 'ember';
import AuthorDatas from 'app-name/mixins/author-data';
export default Ember.Controller.extend(AuthorDatas, {
siteTitle: `Site title`,
fromAuthorData: this.get('authorName'),
// returns πŸ’© - what is the proper syntax?
actions: {
showAuthor() {
var author = this.get('fromAuthorData');
console.log(`Author from controller: ${author}`);
},
},
});
// app/templates/application.hbs
{{fromAuthorData}}
This works...
// app/routes/application.js
import Ember from 'ember';
import AuthorDatas from 'app-name/mixins/author-data';
export default Ember.Route.extend(AuthorDatas, {
afterModel() { // arbitrary
var intro = `Author from route:`;
console.log(`${intro} this.authorName`, this.authorName );
console.log(`${intro} this.get('author-name')`, this.get('authorName') );
},
});
(I would have made an ember-twiddle - but I wasn't sure if Mixins would work the same way ~ since they aren't on the list and there is 0 documentation)
The fromAuthorData property on your controller should be defined like this (I think):
fromAuthorData: Ember.computed('authorName', function() {
return this.get('authorName'); // or whatever derived value you need
}
To understand the problem we need to talk about scope, when you extend/create an object you are merely passing in options, your code is no different than:
let options = {
siteTitle: `Site title`,
// `this` is undefined since we are in strict mode
fromAuthorData: this.get('authorName'),
actions: {
showAuthor() {
var author = this.get('fromAuthorData');
console.log(`Author from controller: ${author}`);
},
}
};
export default Ember.Controller.extend(AuthorDatas, options);
Now to access properties that rely on this being the object holding it you will need a function that is run with the object as it's context that returns that value, enter computed properties.
Your code becomes:
// app/controllers/application.js
import Ember from 'ember';
import AuthorDatas from 'app-name/mixins/author-data';
const { computed } = Ember;
export default Ember.Controller.extend(AuthorDatas, {
siteTitle: `Site title`,
// We add `authorName` as the dependent key, should it change `fromAuthorData` will update
fromAuthorData: computed('authorName', function() {
// your author data stuff
let authorName = this.get('authorName');
// ...
return authorDetails;
}),
actions: {
showAuthor() {
var author = this.get('fromAuthorData');
console.log(`Author from controller: ${author}`);
},
},
});

Ember: computed property (object) not updating in view

I'm new to ember and am creating a search filtering app. I have my search filter "buckets" set up as controller properties and they are bound nicely to query parameters.
I'm looking to create a "your selected filters" component that summarizes what filters the user has currently active. I'm thinking maybe a computed property is the way to do this? In my controller I created one called selectedFilters:
export default Ember.Controller.extend(utils, {
queryParams: ['filter_breadcrumb','filter_price','filter_size_apparel','filter_color'],
filter_breadcrumb: [],
filter_price: [],
filter_size_apparel: [],
filter_color: [],
selectedFilters: Ember.computed('this{filter_breadcrumb,filter_price,filter_size_apparel,filter_color}', function() {
let filterContainer = {};
for (let bucket of this.queryParams) {
let bucketArray = this.get(bucket);
if (bucketArray.length > 0) { // only add if bucket has values
filterContainer[bucket] = {
'title' : cfg.filterTitles[bucket], // a "pretty name" hash
'values' : bucketArray
};
}
}
return filterContainer;
})
});
The contents of selectedFilters would look something like this when a user has chosen filters:
{
filter_breadcrumb: { title: 'Category', values: [ 'Home > Stuff', 'Garage > More Stuff' ] },
filter_price: { title: 'Price', values: [ '*-20.0' ] },
filter_color: { title: 'Color', values: [ 'Black', 'Green' ] }
}
And then the template would be:
<h1>Selected Filters</h1>
{{#each-in selectedFilters as |selectedFilter selectedValues|}}
{{#each selectedValues.values as |selectedValue|}}
<strong>{{selectedValues.title}}</strong>: {{selectedValue}} <br>
{{/each}}
{{/each-in}}
This actually works (kind of). The view is not updating when filters are added and removed. When I hard-refresh the page, they do show up. I'm wondering why they aren't updating even though the "input" properties to selectedFilters do?
I'm thinking either I'm doing it wrong or perhaps there's a better way to do this. Any help appreciated!
You can't use this for computed property dependent key because it's undefined in that scope.
Arrays and objects defined directly on any Ember.Object are shared across all instances of that object. so initialize it in init(). refer initializing instances ember guide
init(){
this._super(...arguments);
this.set('filter_breadcrumb',[]);
}
For definining computed properties using arrays as dependant key refer ember guide
In your case if you want your computed property to recalculate based array item added/removed or changed to different array then use .[]
export default Ember.Controller.extend(utils, {
queryParams: ['filter_breadcrumb', 'filter_price', 'filter_size_apparel', 'filter_color'],
init(){
this._super(...arguments);
this.set("filter_breadcrumb",[]);
this.set("filter_price",[]);
this.set("filter_size_apparel",[]);
this.set("filter_color",[]);
},
selectedFilters: Ember.computed('filter_breadcrumb.[]','filter_price.[]','filter_size_apparel.[]','filter_color.[]', function() {
let filterContainer = {};
for (let bucket of this.queryParams) {
let bucketArray = this.get(bucket);
if (bucketArray.length > 0) { // only add if bucket has values
filterContainer[bucket] = {
'title': cfg.filterTitles[bucket], // a "pretty name" hash
'values': bucketArray
};
}
}
return filterContainer;
})
});
In case if you want computed property to recalculate based on each individual item change then consider filter_price.#each.price
Figured it out. It appears the brace expansion doesn't work on this. I tried:
selectedFilters: Ember.computed('this{filter_breadcrumb,filter_price,filter_size_apparel,filter_color}', function() {
and
selectedFilters: Ember.computed('this.{filter_breadcrumb,filter_price,filter_size_apparel,filter_color}', function() {
This works tho:
selectedFilters: Ember.computed('filter_breadcrumb', 'filter_price', 'filter_size_apparel', 'filter_color', function() {
But I'm still wondering if this is the recommended way of accomplishing my "filter summary" task.

Filter data using params in ember

I'm developing search feature in my app. What I'm trying to do is to filter a car by brand. I have the following in my route:
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
filterCars(car){
this.transitionTo('cars',{ queryParams: {brand: car}});
}
},
queryParams: {
brand: {
refreshModel: true
}
},
model(params) {
if(params['marca'] != null){
this.get('store').query('car', { filter: { brand: params['marca'] } }).then(function(cars) {
return cars;
});
} else {
return this.get('store').findAll('car');
}
}
});
When I get the brand from params, I filter only the cars with that given brand. I thought it would work, but it's not working. Any idea of what I'm doing wrong ?
What is the symptom of your problem?
I notice that your model hook has an if statement with two branches, but only one of them (the else branch) results in the function returning a value. The if branch resolves a promise, but does nothing with it.
Also: is the code you show for the cars route? You may be able to simplify this page by just changing the brand parameter. I'm not sure you need to transition to the same route at all.
Use where clause in filter
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
filterCars(car){
this.transitionTo('cars',{ queryParams: {brand: car}});
}
},
queryParams:{
brand:{
refreshModel: true
}
},
model(params) {
if(params['marca'] != null){
this.get('store').query('car', { filter: { where:{brand: params['marca'] } }}).then(function(cars) {
return cars;
});
} else {
return this.get('store').findAll('car');
}
}
});

emberjs component property not updated?

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

Ember: count number of keys in object?

I have data that looks roughly like this:
"id": "1",
"slug": "WD",
"name": {
"en": "Working Draft",
"de": "Arbeitsentwurf",
"fr": "Version de travail",
"ja": "θ‰ζ‘ˆ",
"ru": "Π Π°Π±ΠΎΡ‡ΠΈΠΉ Ρ‡Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ"
}
And I am passing the name object to a component:
{{title-name name=model.name lang='en'}}
In the component template I would like to output the number of translations
<p>Translated {{translationCount}} times.</p>
I tried a few different things in my component to come up with this total but none of them work. How would I count the number of objects?
export default Ember.Component.extend({
// did not work:
translationCount: Ember.computed.alias('Object.keys(name).length'),
// did not work:
// translationCount: Ember.computed.alias('name.length'),
});
Being a little more explicit about it seems to work:
export default Ember.Component.extend({
translationCount: Ember.computed('name', function() {
return Object.keys('name').length;
})
});
Check out this ember-twiddle for an implementation of this.
Application Template
<h1>Welcome to the {{appName}}</h1>
{{title-name name=data.name lang='en'}}
{{outlet}}
Application Controller
import Ember from 'ember';
export default Ember.Controller.extend({
appName:'Stephanie Hobson App',
data: {
id: 1,
slug: 'WD',
name: {
en: 'Working Draft',
de: 'Arbeitsentwurf',
fr: 'Version de travail',
ja: 'θ‰ζ‘ˆ',
ru: 'Π Π°Π±ΠΎΡ‡ΠΈΠΉ Ρ‡Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ'
}
}
});
title-name.js component
import Ember from 'ember';
var { computed, get } = Ember;
export default Ember.Component.extend({
translationCount: computed('name', function() {
var name = get(this, 'name');
return Object.keys(name).length;
})
});
title-name.hbs component template
{{yield}}
{{translationCount}}