Serialize id in _id format with serializeId in Ember - ember.js

In my response from server i have id attribute like 'id'. But to update record i need to send in request id like '_id'. I try to use serializeId serializeId method. My adapter looks like
import DS from 'ember-data'
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-
mixin'
import Ember from 'ember'
import Inflector from 'ember-inflector'
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:token',
pathForType (modelName) {
let underscored = Ember.String.underscore(modelName)
return Inflector.inflector.pluralize(underscored)
}
})
and voicemail serializer
import ApplicationSerializer from './application'
import DS from 'ember-data'
import Ember from 'ember'
export default ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
primaryKey: 'id',
attrs: {
history: {embedded: 'always'}
},
serializeIntoHash (data, type, snapshot, options) {
let root = Ember.String.decamelize(type.modelName)
data[root] = this.serialize(snapshot, options)
},
serializeId (snapshot, json, primaryKey) {
let id = snapshot.id
json['_id'] = id
}
})
But serializeId method did not called during serializing. And in my payload i still get id like 'id' instead '_id'. How to solve my issue?

UPDATED
I find in ember code that serializeId runs only if ds-serialize-id feature is enabled.
serialize(snapshot, options) {
let json = {};
if (options && options.includeId) {
if (isEnabled('ds-serialize-id')) {
this.serializeId(snapshot, json, get(this, 'primaryKey'));
} else {
const id = snapshot.id;
if (id) {
json[get(this, 'primaryKey')] = id;
}
}
}
To run serializeId method i turn on ds-serialize-id property in enviroment.js
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. 'with-controller': true
'ds-serialize-id': true
}
}
I think that isues solved.

Related

How to get a file from the backend withou getting it JSON-parsed

I’m able to get an xlsx file from my rails backend with a GET-Request to “/companies/export_xslx”, now I’m facing the problem of getting the file passed the JSON parser. For every request the console shows “JSON.parse: unexpected character at line 1 column 1 of the JSON data”.
This is my setup:
//company model ...
exportXlsx: function() {
const adapter = this.store.adapterFor('company');
return adapter.exportXlsx();
}
//adapters/company.js
import DS from 'ember-data';
import TokenAuthorizerMixin from 'ember-simple-auth-token/mixins/token-authorizer';
export default DS.JSONAPIAdapter.extend(TokenAuthorizerMixin, {
exportXlsx() {
const url = 'companies/export_xlsx';
return this.ajax(url, 'GET',
{ dataType: 'text',
accepts: { xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
} });
}
});
I’ll try to alter the default accept header but the requests gets sent with “Accept: application/vnd.api+json”.
I already tried different approaches with “ember-custom-actions” or “ember-cli-file-saver”, they all failed with the JSON.parse… response.
I've found a solution. I tackle the problem in the component with a download service:
// components/companies-download.js
import Component from '#ember/component';
import { computed } from '#ember/object';
import { inject as service } from '#ember/service';
export default Component.extend({
download: service(),
actions: {
downloadXlsx() {
let url = `/companies/export_xlsx`;
this.get('download').file(url);
}
}
});
// services/download.js
import Service from "#ember/service";
import { inject as service } from '#ember/service';
export default Service.extend({
session: service(),
file(url) {
let xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = () => {
let [, fileName] = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(
xhr.getResponseHeader("Content-Disposition")
);
let file = new File([xhr.response], decodeURIComponent(fileName));
let link = document.createElement('a');
link.style.display = 'none';
link.href = URL.createObjectURL(file);
link.download = file.name;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
xhr.open('GET', url);
xhr.setRequestHeader(
'Authorization',
'Bearer ' + this.get('session.data.authenticated.token')
);
xhr.send();
}
});

How to properly use parameters in Ember query?

I have been trying to implement pagination (I've tried both ember-cli-pagination and ember-simple-pagination) for my application but I've had a lot of issues. So I decided to try custom pagination and noticed that I cannot pass parameters into my query. For instance, when visiting my api at: http://jsonplaceholder.typicode.com/posts?_start=0&_limit=10, start and limit both work properly. When calling it in my route, it seems to ignore that entirely and just give me all entries. I would appreciate all insight into what I am doing wrong or how to properly implement pagination in this case.
app/adapters/post.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host:'https://jsonplaceholder.typicode.com',
pathForType(){
return 'posts';
}
});
app/models/post.js
import DS from 'ember-data';
const { Model } = DS;
export default Model.extend({
user:DS.belongsTo('user'),
title:DS.attr('string'),
body:DS.attr('string'),
});
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
You need define the query params in both side Route and Controller.
app/routes/post.js
import Route from '#ember/routing/route';
import { set } from '#ember/object';
import { hash } from 'rsvp';
export default Route.extend({
queryParams = {
start: {
refreshModel: true
},
limit: {
refreshModel: true
}
},
model() {
return hash({
post: this.store.query('post', {
start: 0,
limit: 10
}),
user: this.store.findAll('user')
});
},
setupController(controller, model) {
this._super(...arguments);
set(controller, 'posts', model.post);
set(controller, 'users', model.user);
}
});
And inside app/controllers/post.js
import Controller from '#ember/controller';
export default class ArticlesController extends Controller {
queryParams = ['start', 'limit'];
start = 1;
limit = 5;
}
Ember by default does not call model when query params are changed. We tell it to do so any time start/limit changes, through refreshModel: true.

Setting up admin views with Ember Simple Auth in Ember.js

I'm new to Ember.js and I'm using Ember Simple Auth and I'm having a hard time trying to figure out how to get the current user that is logged in and then checking if the user is an admin so I can display admin only thinks in templates. Currently I am using jwt authentication using Ember Simple Auth Token and a Ruby on Rails backend. Any help in pointing me in the right direction would be great.
I've currently tried getting the example on the Ember Simple Auth to work
https://github.com/simplabs/ember-simple-auth/blob/master/guides/managing-current-user.md
When the user authenticates the jwt is returning the token and the user_id. The issue is that I'm not getting the name or any details about the user when the user is logged in.
I'm trying to access the current user (Which might be wrong) by doing this
{{currentUser.user.name}}
controller/application.js
import Ember from 'ember';
const { inject: { service }, Component } = Ember;
export default Ember.Controller.extend({
session: service('session'),
currentUser: service('current-user')
});
routes/application.js
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
const { service } = Ember.inject;
export default Ember.Route.extend(ApplicationRouteMixin, {
currentUser: service(),
beforeModel() {
return this._loadCurrentUser();
},
sessionAuthenticated() {
this._super(...arguments);
this._loadCurrentUser().catch(() => this.get('session').invalidate());
},
_loadCurrentUser() {
return this.get('currentUser').load();
}
});
services/current-user.js
import Ember from 'ember';
const { inject: { service }, isEmpty, RSVP } = Ember;
export default Ember.Service.extend({
session: service('session'),
store: service(),
load() {
return new RSVP.Promise((resolve, reject) => {
let userId = this.get('session.data.authenticated.user_id');
if (!isEmpty(userId)) {
return this.get('store').find('user', userId).then((user) => {
this.set('user', user);
}, reject);
} else {
resolve();
}
});
}
});
You need to call findRecord
load() {
return new RSVP.Promise((resolve, reject) => {
let userId = this.get('session.data.authenticated.user_id');
if (!isEmpty(userId)) {
return this.get('store').findRecord('user', userId).then((user) => {
this.set('user', user);
resolve();
}, reject);
} else {
resolve();
}
});
}

Ember 1.13 - Recompute helper when global variable change

I got a "get-text" helper which translate my static fields depending on a config variable : ENV.LOCALE.
The thing is, I'd like to recompute my if my ENV.LOCALE gets modified. I tried several things from sending events to Ember.observer, without much success.
// controllers/application.js
locale: function() {
var locale = this.get('isFrench') === true ? 'fr' : 'en';
ENV.LOCALE = locale;
return locale;
}.property('isFrench'),
//helpers/get-text.js
import Ember from 'ember';
import ENV from '../config/environment';
export default Ember.Helper ( function(key, locale) {
var lang = {
save: {
'fr': 'Enregistrer',
'en': 'Save',
},
}
return new Ember.Handlebars.SafeString(lang[key][ENV.LOCALE]);
});
Bottom line, how can I recompute my helper when a global property changes?
After digging threw the documentation, I found this chapter about dependency injection. This combined with the API documentation on Ember.Helper I came up with the following solution :
1st I created a service "locale-manager"
// services/locale-manager.js
import Ember from 'ember';
export default Ember.Service.extend({
isFrench: true,
locale: function() {
var locale = this.get('isFrench') === true ? 'fr' : 'en';
return locale;
}.property('isFrench'),
});
Then I inject my service into my helper and recompute it everytime time the property of locale is changed.
// helpers/get-text.js
import Ember from 'ember';
export default Ember.Helper.extend({
localeManager: Ember.inject.service(),
onLocaleChange: Ember.observer('localeManager.locale', function() {
this.recompute();
}),
compute(params) {
var key = params[0];
var lang = {
enregistrer: {
'fr': 'Enregistrer',
'en': 'Save',
},
var locale = this.get('localeManager.locale');
return new Ember.Handlebars.SafeString(lang[key][locale]);
}
});

Ember Services - Create default settings for application

My app has a lot of reports, and I have dateBegin and dateEnd in all of then.
The desired behaviour is:
app first load, dateBegin = month begin (jun-01) / dateEnd = today (jun-11)
when user change dates (let's say to mai-01 / mai-31), all controllers get the new dates
The code that I have now:
// app/services/defaults.js
import Ember from 'ember';
export default Ember.Service.extend({
init: function () {
this._super();
var dateEnd = moment().format('YYYY-MM-DD');
var dateBegin = moment().startOf('month').format('YYYY-MM-DD'));
if (!this.get('dateEnd')) { this.set('dateEnd', dateEnd); }
if (!this.get('dateBegin')) { this.set('dateBegin', dateBegin }
}
});
// app/components/select-dates-in-reports.js
import Ember from 'ember';
export default Ember.Component.extend({
defaults: Ember.inject.service(),
displayDateBegin: null,
displayDateEnd: null,
dateBegin: Ember.computed.alias('defaults.dateBegin'),
dateEnd: Ember.computed.alias('defaults.dateEnd'),
setInitialParams: Ember.on('init', function () {
this.set('displayDateBegin', this.get('dateBegin'));
this.set('displayDateEnd', this.get('dateEnd'));
}),
actions: {
chooseParams: function () {
this.set('dateBegin', this.get('displayDateBegin'));
this.set('dateEnd', this.get('displayDateEnd'));
}
}
});
// app/mixins/query-params-for-reports.js
import Ember from 'ember';
export default Ember.Mixin.create({
queryParams: ['dateBegin', 'dateEnd'],
defaults: Ember.inject.service(),
dateBegin: Ember.computed.alias('defaults.dateBegin'),
dateEnd: Ember.computed.alias('defaults.dateEnd')
});
// app/mixins/routes-query-params-for-reports.js
import Ember from 'ember';
export default Ember.Mixin.create({
queryParams: {
dateBegin: {
refreshModel: true
},
dateEnd: {
refreshModel: true
}
},
model: function(params) {
return this.store.find(this.get('modelName'),
{
dateBegin: params.dateBegin,
dateEnd: params.dateEnd
}
);
}
});
It works as desired just after each controller is initialized:
user enter the app, and visit controller1. dateBegin = jun-01 / dateEnd = jun-11
on the same controller1, user change dates to dateBegin = mai-01 / dateEnd = mai-31
user visit controller2. Here is the Problem. The dates are set to dateBegin = jun-01 / dateEnd = jun-11
on the same controller2, user change dates to dateBegin = apr-01 / dateEnd = apr-30
user visit controller1 again. Now it works. The dates are set to dateBegin = apr-01 / dateEnd = apr-30
I tried all I could find over the net.
Create Initializers, used localStorage, etc. Nothing works.
Can anyone helps me??
thanks!
Ember Dependency Injection to the rescue!
You can create a singleton object to hold the dates:
App.SelectedDates = Ember.Object.extend({
dateBegin: null,
dateEnd: null // or whatever value you want...
});
Then, inject that object into ALL controllers like this:
Ember.Application.initializer({
name: 'register-global-dates',
initialize: function(container,app) {
app.register('my:globalDate', App.SelectedDates.create(), {
singleton: true,
instantiate: false
});
app.inject('controller', 'dateglobal', 'my:globalDate');
}
});
Now, in your controller(s), you can do this:
this.dateglobal.set('dateBegin', '2015/01/12');
It's the same object in all controllers.
I hope I am understanding your problem correctly and that this is the solution...