get from model and then set a new property on it - ember.js

I have a component:
App.MyChildComponent = Ember.Component.extend({
addTooltips: Ember.on('didInsertElement', function() {
var me = this;
var metrics = this.get('option.metrics');
metrics.forEach(function(e, i) {
me.get('option.metrics').objectAt(i - 1).set('tooltipDisabled', true);
});
});
})
Which is generated inside an each loop by a different component:
App.MyParentComponent = Ember.Component.extend({
...
})
And the template of MyParentComponent is:
{{#each option in options}}
{{my-child option=option}}
{{/each}}
All this, is called by a view with a template like this:
{{my-parent options=options}}
options is defined in the model of the view with:
App.MyViewModel = Ember.Object.extend({
options: Ember.A([
{ metrics: Ember.A([
{ name: 'a' },
{ name: 'b' },
{ name: 'c' }
]) },
{ metrics: Ember.A([
{ name: 'd' },
{ name: 'e' },
{ name: 'f' }
]) },
{ metrics: Ember.A([
{ name: 'g' },
{ name: 'h' },
{ name: 'i' }
]) }
]),
});
When I run me.get('option.metrics').objectAt(i - 1).set('tooltipDisabled', true); I get:
Uncaught TypeError: me.get(...).objectAt(...).set is not a function
What am I doing wrong?

Vanilla JavaScript objects don't have set methods. Use Ember.Objects instead:
App.MyViewModel = Ember.Object.extend({
options: Ember.A([
{ metrics: Ember.A([
Ember.Object.create({ name: 'a' }),
// ...
]) }
]),
});
Demo.

Related

Vue router permission based on User Role from Django Rest Framework

I have Django and Vue project and I need to add permissions in the Vue router based on user role.
I managed to do this in the template by accessing the user data from my user API.
<li class="nav-item active mx-1 mb-1">
<router-link
v-if="user_data.role != 2"
:to="{ name: 'activities' }"
class="btn btn-sm btn-success"
>Activities
</router-link>
</li>
<script>
import { apiService } from "#/common/api.service.js";
export default {
name: "NavbarComponent",
data() {
return {
user_data: {},
}
},
methods: {
setRequestUser() {
this.requestUser = window.localStorage.getItem("username");
},
getUserData() {
// get the details of a question instance from the REST API and call setPageTitle
let endpoint = `/api/user/`;
apiService(endpoint)
.then(data => {
this.user_data = data;
})
},
},
computed: {
isQuestionAuthor() {
return this.requestUser === 'admin_user';
},
isUser() {
return this.requestUser;
},
},
created() {
this.setRequestUser()
this.getUserData()
}
};
</script>
The user doesn't see the button but can still access the pages if enter the path directly in URL.
I can't find a workaround to get the same user data from user API and use it to manage route permissions based on user.role
My router.js looks like this:
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home
},
{
path: "/activities",
name: "activities",
component: Activities
},
{
path: "/add-activity/:slug?",
name: "activity-editor",
component: ActivityEditor,
props: true
},
{
path: "/activities/:slug",
name: "activity",
component: Activity,
props: true
},
{
path: "/cto-entries",
name: "cto-entries",
component: CTOEntries,
},
{
path: "/add-cto-entry/:slug?",
name: "cto-editor",
component: CTOeditor,
props: true
},
{
path: "/question/:slug",
name: "question",
component: Question,
props: true
},
{
path: "/ask/:slug?",
name: "question-editor",
component: QuestionEditor,
props: true
},
{
path: "/answer/:id",
name: "answer-editor",
component: AnswerEditor,
props: true
},
{
path: "*",
name: "page-not-found",
component: NotFound
}
];
const router = new VueRouter({
mode: "history",
//base: process.env.BASE_URL,
routes
});
export default router;
Is there any way to do this in vue router or there is a better way?
I am new to Vue.js, please help :)
Solved this by using beforeEnter and fetching user role from API...
import { apiService } from "#/common/api.service.js";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: Home
},
{
path: "/activities",
name: "activities",
component: Activities,
beforeEnter(to,from,next) {
var user_data = {};
let endpoint = `/api/user/`;
apiService(endpoint)
.then(data => {
user_data = data;
if(user_data.role!=2){
next();
} else {
next("/");
}
});
},
},

Ember sideload data not linked

I'm new to using Ember and was assigned to an ongoing project and need to resolve the following:
export default class OrderModel extends Model.extend(LoadableModel) {
#attr('string') status;
#attr('number') total;
#hasMany('order-item', { async: true }) orderItems;
}
export default class OrderItemModel extends Model.extend(LoadableModel) {
#attr('number', { defaultValue: 0 }) discount;
#attr('number', { defaultValue: 0 }) price;
#hasMany('item-fix', { async: false }) fixes;
}
export default class ItemFixModel extends Model.extend(LoadableModel) {
#attr('number', { defaultValue: 0 }) price;
}
and when I do let order = await this.store.findRecord('order', order_id, { reload: true });
the json response is:
data: {
type: "orders",
id: "1584",
attributes: {
status: "in_progress",
total: 1300
},
relationships: {
order-items: {
data: [
{
type: "order-items",
id: "1801
}
]
}
}
},
included: [
{
type: "order-items"
id: "1801",
attributes: {
discount: 0,
price: 1200
},
relationships: {
item-fixes: {
data: [
{
type: "item-fixes",
id: "335"
}
]
}
},
{
type: "item-fixes",
id: "335",
attributes: {
price: 100
}
}
]
but when I inspect the orderItem inside the order variable, the itemFixes are empty, but the is in the sideload of the response.
¿How can I link this nested relationship?
Also, here is the serializer.
export default DS.JSONAPISerializer.extend({
serialize(snapshot) {
let serialized = this._super(...arguments);
let { adapterOptions } = snapshot;
if (adapterOptions && adapterOptions.addPromotionCode) {
return { code: serialized.data.attributes.code }
}
serialized.included = A([]);
snapshot.eachRelationship((key, relationship) => {
if (relationship.kind === 'belongsTo') {
if (!isBlank(snapshot.belongsTo(key))) {
let node = snapshot.belongsTo(key).record.serialize({ includeId: true }).data;
delete node.relationships;
serialized.included.pushObject(node);
}
} else if (relationship.kind === 'hasMany') {
if (!isBlank(snapshot.hasMany(key))) {
snapshot.hasMany(key).forEach(ele => {
let node = ele.record.serialize({ includeId: true }).data;
delete node.relationships;
serialized.included.pushObject(node);
});
}
}
});
return serialized;
}
});
In your response the relationship name is item-fixes but in your model it's just fixes. It must be the same.

Filter models by related model (hasMany)

I have a list of products with related tags. I want to filter the list to only show products that have the specified tag:
App.Product = DS.Model.extend({
tags: DS.hasMany('Tag', { async: true }),
name: DS.attr( 'string' )
});
App.Tag = DS.Model.extend({
name: DS.attr('string')
});
App.ProductsTaggedRoute = Ember.Route.extend({
model: function(params) {
var store = this.store;
return store.find('product').then(function() {
store.filter('product', function(product, index, enumerable) {
var match = false;
product.get('tags').then(function(tags) {
tags.forEach(function(tag) {
if(tag.get('name') === 'Tag 1') {
console.log(product.get('name') + ' true');
match = true;
} else {
console.log(product.get('name') + ' false', tag.get('name'));
}
});
});
return match;
});
});
}
});
App.Product.FIXTURES = [
{ id: 1, tags: [1,2,3], name: "test 1" },
{ id: 2, tags: [3], name: "test 2" },
{ id: 3, tags: [2,1], name: "test 3" },
{ id: 4, tags: [], name: "test 4" }
];
App.Tag.FIXTURES = [
{ id: 1, name: "Tag 1" },
{ id: 2, name: "Tag 2" },
{ id: 3, name: "Tag 3" },
{ id: 4, name: "Tag 4" }
];
The output is:
test 2 false undefined
test 3 false undefined
test 3 false undefined
test 1 true
test 1 false Tag 2
test 1 false Tag 3
I don't understand why the first three are undefined? Also, I don't get any output in the template so it seems like the filter function isn't right:
{{#each controller}}
{{ name }}
{{/each}}
You'll need to make sure the records are resolved before using the filter on it. This is a perfect use case for promises. You return a promise, and control what's resolved and when.
http://emberjs.jsbin.com/OxIDiVU/84/edit
model: function(params) {
var store = this.store;
return new Em.RSVP.Promise(function(resolve){
//find products
store.find('product').then(function(products) {
// get all the tag promises
var promiseArr = products.getEach('tags');
//wait on them
Em.RSVP.all(promiseArr).then(function() {
var filter = store.filter('product', function(product, index, enumerable) {
var match = false;
product.get('tags').forEach(function(tag) {
if(tag.get('name') === 'Tag 1') {
console.log(product.get('name') + ' true');
match = true;
} else {
console.log(product.get('name') + ' false', tag.get('name'));
}
});
return match;
}); //filter
resolve(filter);
}); // RSVP All
}); //find
}); // promise
}

Not getting record on itemtap sencha list

When Taping items the listener is getting invoked but the value is null. My Code:
Ext.define('tablet.SelectCategories', {
extend: 'Ext.navigation.View',
xtype: 'selectcategorypanel',
id: 'SelectCategories',
requires:[
],
initialize:function(){
this.callParent();
var jsonObject = Ext.create('Tablet')
.make_webservice_call_post('get_categories');
Ext.getCmp('select_category_list')
.setData(jsonObject.info);
console.log(jsonObject.info);
},
config: {
//title : 'Select Categories',
//iconCls: 'team',
//styleHtmlContent: true,
// scrollable: true,
layout: {
type: 'card'
},
items: [
{
fullscreen: true,
mode: 'MULTI',
xtype: 'list',
itemTpl: '{name}',
autoLoad: true,
id:'select_category_list',
store: {
fields: ['active','created','description','name']
},
listeners: {
itemtap: function (list, records) {
console.log('Sel');
console.log(records.name);
var names = [];
Ext.Array.each(records, function (item) {
names.push('<li>' + item.data.name + '</li>');
}); // each()
Ext.Msg.alert('You selected ' + records.length + ' item(s)',
'<ul>' + names.join('') + '</ul>');
} // selectionchange
}
// handler:self.itemClick
}
Getting undefined in console.log(records.name);
Your method signature for itemtap is also wrong. It should be -
itemtap: function(list, index, target, record) {
console.log('Item tapped');
console.log(record.get('name'));
// and your rest of the code.
}
Check the documentation for the itemtap event here, and read up more about stores here.

ember Uncaught Error: assertion failed: Emptying a view in the inBuffer state

I get this assertion when run the code below:
Emptying a view in the inBuffer state is not allowed and should not
happen under normal circumstances. Most likely there is a bug in your
application. This may be due to excessive property change
notifications.
Link to demo:
http://plnkr.co/edit/s3bUw4JFrJvsL690QUMi
var App = Ember.Application.create({
Store: DS.Store.extend({
revision: 4,
adapter: DS.FixtureAdapter.create()
}),
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router){
var person;
person = App.Person.find(657);
person.addObserver("isLoaded", function() {
return router.get('router.applicationController').connectOutlet("things", person.get("things"));
});
}
})
})
}),
ApplicationController: Em.Controller.extend(),
ApplicationView: Em.View.extend({
template: Em.Handlebars.compile("{{outlet}}")
}),
ThingsController: Em.ArrayController.extend({
thingTypes: (function() {
return App.ThingType.find();
}).property()
}),
ThingsView: Em.View.extend({
template: Em.Handlebars.compile([
'{{#each controller.thingTypes}}',
'{{this.name}}',
'{{/each}}',
'{{#each controller.content}}',
'{{this.title}}',
'{{/each}}'].join(""))
}),
//MODELS
Person: DS.Model.extend({
things: DS.hasMany('App.Thing', {
embedded: true
})
}),
Thing: DS.Model.extend({
description: DS.attr('string'),
thingType: DS.belongsTo("App.ThingType", {
embedded: true
}),
title: (function() {
return this.get("thingType.name");
}).property("description")
}),
ThingType: DS.Model.extend({
name: DS.attr("string")
})
});
App.Person.FIXTURES = [
{
id: 657,
things: [
{
id: 1,
description: "Some text",
thing_type: {
id: 1,
name: "type 1"
}
}, {
id: 2,
description: "Some text",
thing_type: {
id: 2,
name: "type 2"
}
}
]
}
];
App.ThingType.FIXTURES = [
{
id: 1,
name: "type 1"
}, {
id: 2,
name: "type 2"
}, {
id: 3,
name: "type 3"
}
];
Why is this happening?
I was having the same error while trying to load a list of dropdown values from fixtures. What resolved it was overriding queryFixtures on the fixture adapter:
App.FixtureAdapter = DS.FixtureAdapter.extend
latency: 200
queryFixtures: (records, query, type) ->
records.filter (record) ->
for key of query
continue unless query.hasOwnProperty(key)
value = query[key]
return false if record[key] isnt value
true
I probably wouldn't have figured it out had I not set the latency first. Then the error was a bit more descriptive.
a bit late I guess... but I got it to work here:
http://plnkr.co/edit/hDCT4Qy1h5aE6GjM76qp
Didn't change the logic but where its called
I modified your router like this:
Router: Ember.Router.extend({
root: Ember.Route.extend({
index: Ember.Route.extend({
route: "/",
connectOutlets: function(router) {
var person;
router.set('router.applicationController.currentPerson', App.Person.find(657));
}
})
})
})
And created an ApplicationController:
ApplicationController: Em.Controller.extend({
currentPerson: null,
currentPersonLoaded: function() {
this.connectOutlet("things", this.get("currentPerson.things"));
}.observes("currentPerson.isLoaded"),
})
I dont know if this is the output you wished but the bug vanished!