Download files in ember: using Ember-cli-file-saver - ember.js

It might be plain ignorance from my part but I have only managed to download a file generated by the api using the model method mention in the documentation. Using a component I am quite blind.
The specific question would be: where do I pass the mention arraybuffer:true to the application adapter or to a custom ajax request? Do you have a working example?
Here is a simple try using an ajax service:
import Component from '#ember/component';
import FileSaverMixin from 'ember-cli-file-saver/mixins/file-saver';
import { inject as service } from '#ember/service';
export default Component.extend(FileSaverMixin, {
tagName: 'div',
ajax: service(),
store: service(),
click() {
this.get('ajax').request('/excel', {
options: {
arraybuffer: true
}
}
).then((content) => {
console.log(content);
this.saveFileAs(this.get('filename'), content, this.get('contentType'));
}).catch((error) => {
console.log(error);
})
}
});
And this is my adapter:
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import AdapterArrayBufferMixin from 'ember-cli-file-saver/mixins/adapter-arraybuffer-mixin';
import ENV from 'efac-front/config/environment';
export default DS.JSONAPIAdapter.extend(
DataAdapterMixin,
AdapterArrayBufferMixin,
{
authorizer: 'authorizer:token',
namespace: 'api',
host: ENV.host
}
);
I keep getting an error of SyntaxError: Unexpected token P in JSON at position 0... because it is trying to interpret an array buffer or binary response as json data.
I very much appreciate any light you can throw here

Well it was super easy, but not very well documented. I just needed to add the dataType key to my ajax request like this:
this.get('ajax').request('/excel', {
dataType: 'arraybuffer',
options: {
arraybuffer: true
}
}
).then((content) => {
this.saveFileAs('reporte-asistencia.xlsx', content, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
}).catch((error) => {
console.log(error);
});
It can also be done with dataType: 'blob'.

Related

How to use asynchronous service in ember.js?

Before my ember.js app start, I need to access a entry api to get all those api endpoints and csrf token.
I'm trying to do it in service so the response can be accessed everywhere:
import Service from '#ember/service';
import $ from 'jquery'
export default Service.extend({
pageData: null,
init () {
this._super(...arguments)
var self = this
$.ajax({
type: 'get',
url: '/page_data',
dataType: 'json'
}).then((response) => {
self.set('pageData', response)
})
}
});
And I'm injecting the service in initializer:
export function initialize (application) {
application.inject('route', 'api', 'service:page-data');
application.inject('controller', 'api', 'service:page-data');
application.inject('component', 'api', 'service:page-data');
}
export default {
initialize
};
But I can't use the service in my router directly with this.get('api').pageData because it's asynchronous.
I found something on ember.js documentation here:
Operations performed in initializers should be kept as lightweight as possible to minimize delays in loading your application. Although advanced techniques exist for allowing asynchrony in application initializers (i.e. deferReadiness and advanceReadiness), these techniques should generally be avoided. Any asynchronous loading conditions (e.g. user authorization) are almost always better handled in your application route's hooks, which allows for DOM interaction while waiting for conditions to resolve.
But it 's used in initializers, not service.
Any suggests what I can do with my service now?
You can use application's deferReadiness method, to stall your app load.
However, if you require a loading UI, i would suggest to set a promise object to your pageData variable, and as soon as that promise resolves/rejects you can change the state of your app accordingly.
Here's what I did at last:
import Service from '#ember/service';
import $ from 'jquery'
import { Promise } from 'rsvp'
export default Service.extend({
pageData: null,
setup () {
return new Promise((resolve, reject) => {
var self = this
$.ajax({
type: 'get',
url: '/page_data',
dataType: 'json'
}).then((response) => {
self.set('pageData', response)
resolve()
}).catch(() => {
reject()
})
})
}
});
Then in the index route, run the setup in beforeModel hook:
import Route from '#ember/routing/route';
import { all } from 'rsvp'
export default Route.extend({
beforeModel () {
return all([this.get('api').setup()])
},
model () {
window.console.log(this.get('api').pageData)
}
});

Ember simple auth doesn't send auth header to api

I'm trying make authorization in my ember application.
Its working on client side, but ember doesn't attach Bearer token to api request.
My adapter
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
host: 'http://localhost/money-app-api/web/app_dev.php/api',
authorizer: 'authorizer:application'
});
My authorizer:
import Ember from 'ember';
import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer';
const { isEmpty } = Ember;
export default OAuth2Bearer.extend({
authorize(data, block) {
const accessToken = data['access_token'];
if (!isEmpty(accessToken)) {
block('Authorization', `Bearer ${accessToken}`);
}
accessToken in authorizer is exists and is correct.
My api is correct too, i tested it by Postman.
I am writing you a full tutorial please just follow that hope it works for you.
//folders and files tree
adapters
--- application.js
authenticators
--- oauth2.js
authorizers
---- oauth2-bearer.js
Adapters/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
export default DS.JSONAPIAdapter.extend(DataAdapterMixin,{
authorizer: 'authorizer:oauth2-bearer',
host: 'http://localhost/money-app-api/web/app_dev.php',
namespace: 'api'
});
authenticators/oauth2.js
import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant';
export default OAuth2PasswordGrant.extend({
serverTokenEndpoint: 'http://localhost/money-app-api/web/app_dev.php/token'
});
authorizers/oauth2-bearer.js
export { default } from 'ember-simple-auth/authorizers/oauth2-bearer';
so now in your route, application.js, you are able to use the following code: this is just for demo purpose you need to modify as you need.
this.get('session').authorize('authorizer:oauth2-bearer', (headerName, headerValue) => {
headers[headerName] = headerValue;
});
I am writing an authentication in route/application.js to clarify more. in this example I am getting Account and User information based on session which has already authenticated .
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
import config from '../config/environment';
export default Ember.Route.extend(ApplicationRouteMixin, {
model() {
return Ember.RSVP.hash({
account: new Ember.RSVP.Promise((resolve, reject) => {
if (!this.get('session.isAuthenticated')) {
resolve({});
return;
}
let store = this.store,
session = this.get('session');
let headers = {};
this.get('session').authorize('authorizer:oauth2-bearer', (headerName, headerValue) => {
headers[headerName] = headerValue;
});
return Ember.$.ajax(config.apiUrl + '/api/account', {
headers: headers
}).then(data => {
if (data) {
store.pushPayload(data);
resolve(store.peekRecord('user', data.data.id));
} else {
reject({});
session.invalidate();
}
}).fail(() => {
session.invalidate();
});
})
});
},
sessionAuthenticated() {
this.refresh();
this._super();
}
});
I hope, this can solve your problem.
an important tip:
The REST adapter allows your store to communicate with an HTTP server by
transmitting JSON via XHR. Most Ember.js apps that consume a JSON API
should use the REST adapter.
### Headers customization
Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary
headers can be set as key/value pairs on the `RESTAdapter`'s `headers`
object and Ember Data will send them along with each ajax request.
```app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
headers: {
"API_KEY": "secret key",
"ANOTHER_HEADER": "Some header value"
}
});
```
`headers` can also be used as a computed property to support dynamic
headers. In the example below, the `session` object has been
injected into an adapter by Ember's container.
```app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
headers: Ember.computed('session.authToken', function() {
return {
"API_KEY": this.get("session.authToken"),
"ANOTHER_HEADER": "Some header value"
};
})
});
```
Source
My only problem was that i have not authorization in my accept headers in api
allow_headers: ['origin', 'X-Custom-Auth', 'Content-Type', 'Authorization']
That is strange, because when tested by Postman all was working.

Emberjs: cannot read property 'type' of undefined

I have created a model in my ember app called ticket-stats:
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
export default Model.extend({
get_tickets_more: attr(),
get_tickets: attr(),
get_avg_tickets: attr()
});
The data is pulled from JSON api: http://domain.com/data/ticketStats?blah=blah...
So i have added a special adapter for this model called ticket-stats:
import JSONAPIAdapter from 'ember-data/adapters/json-api';
export default JSONAPIAdapter.extend({
host: 'http://domain.com',
namespace: 'data',
pathForType: function(type) {
return Ember.String.camelize(type);
}
});
I get the data for this model in route:
import Ember from 'ember';
export default Ember.Route.extend({
model () {
var ticketData;
this.store.query('ticket-stats', { teamID: 218, attUID: 'oc7569', useProd: 1})
.then(function(stats) { ticketData = stats; });
return Ember.RSVP.hash({
currentUser: this.currentUser,
ticketStats: ticketData
});
}
});
And, i get a TypeError:
ember.debug.js:32096 TypeError: Cannot read property 'type' of undefined
at _pushInternalModel (store.js:1524)
at push (store.js:1501)
at finders.js:171
at Object.Backburner.run (ember.debug.js:678)
at _adapterRun (store.js:1733)
at finders.js:168
at tryCatch (ember.debug.js:53806)
at invokeCallback (ember.debug.js:53821)
at publish (ember.debug.js:53789)
at ember.debug.js:32054onerrorDefault # ember.debug.js:32096exports.default.trigger # ember.debug.js:54476(anonymous function) # ember.debug.js:55727Queue.invoke # ember.debug.js:333Queue.flush # ember.debug.js:397DeferredActionQueues.flush # ember.debug.js:205Backburner.end # ember.debug.js:560(anonymous function) # ember.debug.js:1126
Any ideas as to why this is happening? This error goes away when i remove the pathForType function in the adapter, but then i get another error about getting the data from http://domain.com/data/ticket-stats?... which is not the correct URL. I have to convert to camelCase, ticket-stats => ticketStats.
This is what my json looks like:
{
"get_avg_tickets": { ... },
"get_tickets_more": { ... },
"get_tickets": { ... }
}
I also modified the application serializer by simply replacing JSONAPISerializer with JSONSerializer: app/serializers/application.js
import JSONSerializer from 'ember-data/serializers/json';
export default JSONSerializer.extend({
});
Any help would be appreciated! I'm very new to Ember.
you need to use this serializer here is the reference link
http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
normalizeQueryResponse(store, primaryModelClass, payload, id, requestType) {
payload = { ticketStats: payload };
return this.normalizeArrayResponse(store, primaryModelClass, payload, id, requestType);
},
});
your json should be in this format:
{
"get_avg_tickets": 45,
"get_tickets_more": propertyvalue,
"get_tickets": propertyvalue
}
otherwise you need to normalize your response in normalizeQueryreponse of serilializer
Also ready following doc for your help
http://thejsguy.com/2015/12/05/which-ember-data-serializer-should-i-use.html
i hope it will help you. dont forget to accept my answer.
you need to use serializers which are best suited for your json data.
http://emberjs.com/api/data/classes/DS.JSONAPISerializer.html
This error is raising because your json data received from api is not fully fit into you application requirements for json formate.
Please Share json data here. because domain.com json url is not working.
there are so many issues in your code. let me to guide you one by one

ember-simple-auth overriding sessionAuthenticated

Folks,
I've been trying to get ESA to redirect to specific pages after login and logout events without success.
I'm trying to do this by overriding the "sessionAuthenticated" method, but have also tried setting the "routeAfterConfiguration" setting with no luck.
At the moment, login sends me to "/", and logout sends the app to "/undefined".
I'm using simple-auth-token as a JWT authenticator strategy.
The code for my application route looks like this...
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default Ember.Route.extend(ApplicationRouteMixin,{
actions: {
sessionAuthenticated: function() {
console.log('sessionAuthenticated: authentications ok');
window.location.replace('/profile');
},
},
});
My login.js is as follows:
import Ember from 'ember';
const {service} = Ember.inject;
export default Ember.Route.extend({
session: service('session'),
errorMessage: null,
model: function(){
return Ember.Object.create({
identification:'',
password: '',
errorMessage: this.get('errorMessage')
});
},
setupController: function(controller, model) {
controller.set('credentials',model);
},
actions: {
authenticate: function(credentials) {
console.log(credentials);
this.get('session').authenticate('simple-auth-authenticator:jwt', credentials)
.catch((reason) => {
console.log('Login Error');
credentials.set('errorMessage', reason);
});
},
},
});
Does anyone have any idea what I might be doing wrong here?
Cheers,
Andy
OK. Found the problem. These are not actions - they're methods. So I just had to promote the methods out of the actions object and it's all come good.
So the correct routes/application.js looks like this:
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default Ember.Route.extend(ApplicationRouteMixin,{
sessionAuthenticated: function() {
console.log('sessionAuthenticated: authentications ok');
window.location.replace('/profile');
},
});

Ember-simple-auth custom authorizer not called

I'm trying to implement custom auth with ember-simple-auth and I stuck at the start. I have app/autheticators/digest.js
import Base from 'ember-simple-auth/authenticators/base';
import Ember from 'ember';
export default Base.extend({
restore(data) {
//
},
authenticate(email, password) {
console.log(email, password);
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run(function() {
resolve({email: email, password: password});
});
});
},
invalidate(data) {
//
}
});
app/authorizers/digest.js
import Base from 'simple-auth/authorizers/base';
import Ember from 'ember';
export default Base.extend({
header: function() {
return "test-digest";
},
authorize: function(sessionData, block) {
console.log('authorize...');
block('Authorization', this.get('header'));
}
});
Login component:
import Ember from 'ember';
import CryptoJS from 'npm:crypto-js';
export default Ember.Component.extend({
session: Ember.inject.service('session'),
actions: {
login() {
let { email, password } = this.getProperties('email', 'password');
this.get("session").authenticate('autheticator:digest',
email, CryptoJS.SHA256(password).toString()).catch((reason) => {
this.set('errorMessage', reason.error);
});
}
}
});
Authentication called properly (I hope), but "authorize" in authorizer never called. I also tried add some values to ENV:
ENV['simple-auth'] = {
authorizer: 'authorizer:digest',
crossOriginWhitelist: ['http://prod-drunkedguru.rhcloud.com:80/'] // ['*'] I also tried
};
But nothing changed. What I'm doing wrong?
P.S. I'm using EmberJS 1.13.0 with EAS 1.0.
I assume you're using ESA 1.0. In that version the authorizer isn't automatically called anymore but you need to call it manually. There is the DataAdapterMixin that you can use to automatically authorizer Ember Data requests though. See this blog post for guidance on migrating to 1.0: http://log.simplabs.com/post/131698328145/updating-to-ember-simple-auth-10