How to load XML data from HTTP request in ember 2.1 - ember.js

I am new in Ember.js and I am having trouble connecting my app to the backend data.
I am currently using ember data v.2.1, ember v.2.1, ember inspector v.1.9.3
We are upgrading an existing app and we want to use ember as front-end framework. The app right now is java based and is using xsl on the front.
What I need to do is to connect through HTML request with ember to the existing backend which return XML and convert it to json so I can use it in ember. I tried to follow this example : https://bendyworks.com/old-new-soap-ember-js/ without any luck.
With the inspector I can see my model, but I can't load any data in it.
I have a model that look like this:
// app/models/get-menu.js
import DS from 'ember-data';
export default DS.Model.extend({
description: DS.attr('string'),
url: DS.attr('string')
});
I have an adapter:
//adapters/menu.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
headers: {
'Content-Type': 'text/xml;charset=UTF-8'
},
findAll: function() {
return this.ajax('LinkForHTTPRequest','POST');
},
ajaxOptions: function(url) {
// pretend to be a 'GET' to avoid certain nastiness in default impl
var hash = DS.RESTAdapter.prototype.ajaxOptions.call(this, url);
hash.type = 'GET';
hash.dataType = 'xml';
return hash;
}
});
and I have a serializer :
import DS from 'ember-data';
import Ember from 'ember';
export default DS.JSONSerializer.extend({
extractArray: function(store, xmlDoc) {
var $ = Ember.$;
var xml = $(xmlDoc).find('TMSMENUS').text();
var innerXml = $($.parseXML(xml)).find('MENUS');
return innerXml.map(function(idx, el) {
return {
id: idx,
name: $(el).find('description').text(),
url: $(el).find('url').text(),
};
}).get();
}
});

Related

Handle multiple API in a single app with similar model type

I have two APIs, let's say :
aaa.com/api/v1/events
bbb.com/api/events
Both implement JSONAPI adapter, and then return a payload with type="events".
As a result, I have to scope those models into subfolders:
models/aaa/event.js
models/bbb/event.js
Which result in querying the models this way:
this.get('store').findAll('aaa/event');
Then, I have implemented an adapter:
// adapters/aaa/event.js
import config from '../../config/environment';
import DS from 'ember-data';
import Ember from "ember";
const { String } = Ember;
export default DS.JSONAPIAdapter.extend({
host: 'aaa.com',
namespace: 'api/v1',
pathForType: function(type) {
return String
.underscore(type) // `aaa/some-model` -> `aaa/some_model`
.pluralize() // `aaa/some_model` -> `aaa/some_models`
.replace("aaa/", ""); // `aaa/some_model` -> `some_model`
},
});
So far so good, Ember correctly calls aaa.com/api/v1/events, the returned payload is typed events but Ember fails to translate it to aaa/events.
How can I proceed ?
So you got the model specific serializer for aaa/event and bbb/event. you can overridre modelNameFromPayloadType method to translate events to your required model name aaa/events.
For aaa/event serializer,
modelNameFromPayloadType(payloadType) {
return 'aaa/event';
}
Refer:
https://emberjs.com/api/ember-data/2.14/classes/DS.JSONAPISerializer/methods/modelNameFromPayloadType?anchor=modelNameFromPayloadType

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 data not saving foreign key, sent as null

My ember app is not sending my foreign key to the back-end.
I have a table called issues which is has a related table called categories
My model is:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
category_id: DS.belongsTo('category'),
description: DS.attr('string')
});
My route is:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.findAll('issue');
},
actions: {
create: function(){
var issue = this.store.createRecord('issue');
issue.name = this.get('controller').get('newName');
issue.description = this.get('controller').get('newDescription');
issue.category_id = parseInt(this.get('controller').get('newCategory'));
//debugger;
console.log(issue);
issue.save();
},
...
other actions
...
}
}
});
the console.log from above looks like the category_id is getting set correctly:
category_id: 3
description: "foobar"
name: "test"
However my JSON payload that gets sent to the backend looks like:
{"issue":{"name":"test","description":"foobar","category_id":null}}
I tried stepping through by adding a custom serialiser in app/serializers/application.js
export default DS.RESTSerializer.extend({
...
serialize: function(snapshot,options){
console.debug('options='+options);
debugger;
var json = this._super(snapshot, options);;
return json;
}
...
});
But I got lost in all the super calling super indirection.
The snapshot.record has category_id: 3, but the json coming back from the this._super() call has category_id: null
options has includeID:true
Any clues will be much appreciated ...
Ember : 2.0.2
Ember Data : 2.0.0
Your model definition is wrong, when dealing with relationships you define them just as you would define any other attribute, there is no need to use _id.
export default DS.Model.extend({
name: DS.attr('string'),
category: DS.belongsTo('category'),
description: DS.attr('string')
});
As for the creation you should always use setters/getters when dealing with ember objects:
create: function() {
var issue = this.store.createRecord('issue', {
name: this.get('controller').get('newName'),
description: this.get('controller').get('newDescription'),
category: this.get('controller').get('newCategory') // assuming new category is a DS.Model instance of category
});
issue.save();
}
If you wish to stick to the syntax you have you would use issue.set('name', this.get('controller').get('newName')), from the looks of your code it seems you are going about this in the wrong way.
You should have a this.route('new') nested under your issues route, that way you wouldn't have to use the controller to store information.
You would simply set the model of the new route to:
model: function() {
return this.store.createRecord('issue');
}
Your template would make use of the input helpers like so:
{{input value=model.name}} and your action would just get the currentModel and call .save().

Model in Payload not recognized

I have some models with similar names:
issue-statuse.js
issue-type.js
issue-type is working perfectly, but issue-statuse is causing trouble:
WARNING: Encountered "issue_statuses" in payload, but no model was found for model name "issue-status" (resolved model name using soporte#serializer:issue-statuse:.modelNameFromPayloadKey("issue_statuses"))
//<!--app/adapters/application.js-->
import Ember from 'ember';
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: 'api/v1',
host: 'http://127.0.0.1:3000',
coalesceFindRequests: true,
headers: {
withCredentials: true,
Authorization: 'Basic eG9qbzpzZWNyZXQ=',
crossDomain: true
},
pathForType: function(type) {
return Ember.String.underscore(type)+'s';
}
});
// added a 's' for pluralize names, as when we need in underscore are in singular once again ...
//<!--app/models/issue-statuse.js-->
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
short: DS.attr('string'),
plural: DS.attr('string'),
created_at: DS.attr('date'),
active: DS.attr('boolean')
});
I have a workaround in a Serializer, I don't like it but with it it's working fine:
//<<!--app/serializers/issue-statuse.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
modelNameFromPayloadKey: function(payloadKey) {
if (payloadKey === 'issue_statuses') {
return this._super("issue-statuse"); //this._super(payloadKey.replace('blog/', ''));
} else {
return this._super('issue-statuse'); //this._super(payloadKey);
}
}
});
But if I use this Serializer, I've got a Deprecation Warning:
Your custom serializer uses the old version of the Serializer API, with `extract` hooks. Please upgrade your serializers to the new Serializer API using `normalizeResponse` hooks instead.
So, I have two options, first one is try to solve why Ember is not finding my model, and the second, use the serializer and try to understand the deprecation and how to eliminate it.
I would prefer option one :-)
Thanks,
edit
It was a typo here in the name of the model file, it's singular:
//<!--app/models/issue-statuse.js-->
edit 2
I've removed completely the app/serializers/issue-statuse.js and created an initializer with the inflector:
//<!--/app/initializers/inflector.js-->
import Ember from 'ember';
export function initialize(/* container, application */) {
var inflector = Ember.Inflector.inflector;
inflector.uncountable('aamc-pcrs');
inflector.irregular('issue-statuse', 'issue-statuses');
}
export default {
name: 'inflector',
initialize: initialize
};
edit 3
I'm using the
pathForType: function(type) {
return Ember.String.underscore(type)+'s';
},
in the Adaptor for changing - for _
My Backend API wants issue_statuses instead of issue-statuses for example. Maybe I can just rename the table in the inflector and remove also this line ...