Ember JS transformation into Ember Data from using promises - javascript

I have a deep jSon structure to deal with so I currently implement promises directly into the Ember Model (not dependant on Ember Data).
This is shown as follows: -
return Ember.$.getJSON('/ProcessManager/manage type=submitters&action=getSubmitters').then(function(data)
{
var submitters = [];
$.each(data, function(i, item) {
$.each(item, function(i, item) {
$.each(item, function(i, item) {
Push each submitter into submitter array
submitters.push(item);
});
});
});
return submitters;
});
An example complete jSON response from this URL is as follows: -
{"submitters":{"signsubmitter.jar":{"SignSubmitter":{"description":null,"name":"com.form.custom.submitters.SignSubmitter","jarName":"signsubmitter.jar"}},"custom-classes.jar":{"OutputDirSubmitter":{"description":"Writes
the XML to a
directory.","name":"com.form.custom.submitters.OutputDirSubmitter","jarName":"custom-classes.jar"},"XMLResponseSubmitter":{"description":"Returns
the XML file to the
client.","name":"com.form.custom.submitters.XMLResponseSubmitter","jarName":"custom-classes.jar"},"ChainProcess":{"description":"Chain
the output file to another
process.","name":"com.form.custom.submitters.ChainProcess","jarName":"custom-classes.jar"}}},"success":true}
I have read this URL: http://emberjs.com/guides/models/connecting-to-an-http-server/
I would like to know people's opinion on transitioning to Ember Data with this type of data.
Thank you.

I've been using ember data with deeply nested record sets for a while now and I like it a lot. It should work just fine based on my understanding of the info you provided. Ideally you should be able to define the JSON in the format that ember expects see side loaded relationships here. If you get this right then most things are fine. Initially I spent many frustrated hours due to wrong casing and much of the doco is outdated and shows incorrect casing - this is something that you will have to work out for yourself - but if you get the odd meaningless error then casing may be the issue.
If you are unable to change the server JSON then you can simply override the RESTAdapter and RESTSerializer to meet requirements. This is also simple and works.
Ember data works well for me and does what I need it to.
Ember is designed to work with promises and to load deeply nested record sets the order in which these promises resolve can be very important. There is enough info here on SO on how this can be achieved.

Related

Right way to make AJAX GET and POST calls in EmberJS

I've started working on EmberJS and I absolutely love it. It does have a learning curve but I believe it has fundamentally very meaningful principles.
My questions is how to make GET and POST calls in Ember JS. I understand that there are models / store, but models (in my opinion) would be to only a particular entity's attributes.
Any thoughts on the following questions would be great.
1. USER A send friend request to USER B. Should there be a "Request"
model? And do I just make a POST request?
2. Some arbitrary data needs to be returned for the page. Not
particularly of a model. Should I still make a model for that?
For use a simple GET request?
3. User needs to update this profile photo. How can the file
to be uploaded, be set as a model attribute?
How should I go about making regular GET and POST calls (if I am to do them at all). Just use jQuery's $.ajax() or is there another way. I also found a service ember-ajax which has extended the $.ajax into a promises style.
Any thoughts would be much appreciated.
Long live EmberJS :)
First option: You can use ember-data. It has customizations such as serializers or adapters.
Second option: You can use addons like ember-ajax.
Our usage is just using jQuery's ajax(). We wrote a service that just wraps jquery.ajax() and use it everywhere in our code. We believe that it gives us a flexibility of writing different kind of queries. We don't have any model of ember-data.
Sample -pseudo- code:
export default Ember.Service.extend({
doPostCall(target, data, options=null){
//consider cloning options with Ember.$.extend
var requestOptions= options || {};
requestOptions.url=target;
requestOptions.type='POST';
requestOptions.data=JSON.stringify(data);
doRemoteCall(requestOptions);
},
doGetCall(target, data=null, options=null){
//consider cloning options with Ember.$.extend
var requestOptions=options || {};
requestOptions.url=target;
requestOptions.type='GET';
requestOptions.data=data;
doRemoteCall(requestOptions);
},
doRemoteCall(requestOptions){
//assign default values in here:
// such as contentType, dataType, withCredentials...
Ember.$.ajax(requestOptions)
.then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR , textStatus, errorThrown) {
jqXHR.then = null;
Ember.run(null, reject, jqXHR, textStatus, errorThrown);
});
}
});
PS: By the way, if you need to run your app in server-side (with fastboot), you cannot use jQuery. So use ember-network.
If you are performing CRUD operations over models, ember-data is nice. In most apps, CRUD operations account for ~90% of requests.
There is occasions where an app needs to make requests that not ideal for ember-data, and that is where ember-ajax enters the game. It allows you to do requests like you'd do with just jQuery, with the nice addition that requests are done though a service that has some extension points to allow to customize things like headers that are used app-wide, which is more complex with just raw jquery.
If your app is going to run in fastboot, you should use ember-network, because it works both in the browser and in node, while jquery/ember-ajax does don't.
Current best practise would be ember-fetch. since ember-network is deprecated in favor of ember-fetch.
You can just install ember-fetch addon by running the below command,
ember install ember-fetch
and then just import fetch and you are good to use fetch method.
import fetch from 'fetch';
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return fetch('/my-cool-end-point.json').then(function(response) {
return response.json();
});
}
});

Map JSON Object To Something Worthwhile in React

I was wondering if I could get a little advice on pulling in some JSON data in my React app. I have a good amount of experience in front end development, but unfortunately have minimal knowledge when it comes to pulling in data from remote resources.
Here is my sample json data
{
"hello": {
"yo" : "random",
"hey" : "cool"
}
}
This data sits locally and I can pull it in just fine, but I am wondering if there is an easier way to get the data into the format I want. My code is below of what I am doing,
grabData() {
axios.get('data.json')
.then(function(response) {
var info = response.data.hello;
info = Object.values(info);
this.setState({ info : info })
});
}
For those unfamiliar, I am using an ES6 feature to turn the object into an array so I can use the map method in a child component that will receive this array.
However, I think this method is flawed, as it completely strips the object of its keys, which I would like to keep intact to use in the map method. Any help would be greatly appreciated.
PS. Is it really necessary for me to use "response.data.hello" to access the object?

Meteor: Data from External API call not rendering

I am relatively new to Meteor, and I'm trying to create a web store for my sister-in-law that takes data from her existing Etsy store and puts a custom skin on it. I've defined all of my Meteor.methods to retrieve the data, and I've proofed the data with a series of console.log statements... So, the data is there, but it won't render on the screen. Here is an example of some of the code on the server side:
Meteor.methods({
...
'getShopSections': function() {
this.unblock();
var URL = baseURL + "/sections?api_key="+apiKey;
var response = Meteor.http.get(URL).data.results;
return response;
}
...
});
This method returns an array of Object. A sample bit of JSON string from one of the returned Objects from the array:
{
active_listing_count: 20,
rank: 2,
shop_section_id: 1******0,
title: "Example Title",
user_id: 2******7
}
After fetching this data without a hitch, I was ready to make the call from the client side, and I tried and failed in several different ways before a Google search landed me at this tutorial here: https://dzone.com/articles/integrating-external-apis-your
On the client side, I have a nav.js file with the following bit of code, adapted from the above tutorial:
Template.nav.rendered = function() {
Meteor.call('getShopSections', function(err, res) {
Session.set('sections', res);
return res;
});
};
Template.nav.helpers({
category: function() {
var sections = Session.get('sections');
return sections;
}
});
And a sample call from inside my nav.html template...
<ul>
{{#each category}}
<li>{{category.title}}</li>
{{/each}}
</ul>
So, there's a few things going on here that I'm unsure of. First and foremost, the DOM is not rendering any of the category.title String despite showing the appropriate number of li placeholders. Secondly, before I followed the above tutorial, I didn't define a Session variable. Considering that the list of shop categories should remain static once the template is loaded, I didn't think it was necessary from what I understand about Session variables... but for some reason this was the difference between the template displaying a single empty <li> tag versus a number of empty <li>'s equal to category.length --- so, even though I can't comprehend why the Session variable is needed in this instance, it did bring me one perceived step closer to my goal... I have tried a number of console.log statements on the client side, and I am 100% sure the data is defined and available, but when I check the source code in my Developer Tools window, the DOM just shows a number of empty li brackets.
Can any Meteor gurus explain why 1) the DOM is not rendering any of the titles, and 2) if the Session variable indeed necessary? Please let me know if more information is needed, and I'll be very happy to provide it. Thanks!
You set the data context when you use #each, so simply use:
<li>{{title}}</li>
If a Session is the right type of reactive variable to use here or not is hard to determine without knowing what you are doing but my rough guess is that a Mini Mongo collection may be better suited for what it appears you are doing.
To get you started on deciding the correct type of reactive variable to use for this head over to the full Meteor documentation and investigate: collections, sessions, and reactive vars.
Edit: To step back and clarify a bit, a Template helper is called a reactive computation. Reactive computations inside of helpers will only execute if they are used in their respective templates AND if you use a reactive variable inside of the computation. There are multiple types of reactive variable, each with their own attributes. Your code likely didn't work at all before you used Session because you were not using a reactive variable.

breezejs: adding referential constraint to an entity type

This is a follow-up question to my previous issue - this one was getting a bit messy and is more related to the Telerik Data Service.
The metadata I receive from the server are missing the referential constraints in the association node, although I've set the foreign key attribute on my model.
Therefore I was thinking about manually adding these constraints to my entities in the callback of FetchMetadata.
Is that possible and can someone provide a simple example on how to do it ?
[EDIT]
Here's what I have so far:
manager.fetchMetadata().then(function () {
var mandatType = manager.metadataStore.getEntityType("Mandate");
mandatType.autogeneratedKeyType = breeze.AutoGeneratedKeyType.Identity;
var openPositionsProp = new breeze.NavigationProperty({
name: "OpenPositions",
entityTypeName: "OpenPositions:#DirectDebitModel",
isScalar: true,
associationName: "OpenPosition_Mandate_Mandate_OpenPositions",
foreignKeyNames: ["Id"]
});
mandatType.addProperty(openPositionsProp);
});
But it raises the exception:
The 'Mandate:#DirectDebitModel' EntityType has already been added to a MetadataStore and therefore no additional properties may be added to it.
Ok, I have a possible approach that you might be able to use right now.
Fetch the metadata from Teleriks OData feed just like you do now.
Export the metadataStore created as a result of the previous step via the MetadataStore.exportMetadata method. This will return "stringified" json for the same metadata in Breeze's native format. This format is much easier to work with.
Convert this string to json via JSON.parse.
Modify the json to add referential constraint information. See Breeze Native Metadata format docs here
Create a new MetadataStore and import the modified json into it.
Create a new EntityManager with this MetadataStore and use it. This EntityManager should now have complete Breeze metadata for use with the rest of the feed.
Hope this makes sense!
We are planning on releasing a form of hybrid metadata in the next release. Unfortunately, it doesn't cover your case because we are focusing on how to add custom metadata to an existing metadataStore, and not actually edit/modify the existing metadata.
Another alternative is that we (IdeaBlade) do offer consulting for this type of work. We could probably write a tool that does steps 1 thru 6 for you. Please contact breeze#ideablade.com if this is of interest and mention this post.
So you are getting meta data but it doesn't have a relationship between the entities. Hmm I have not gotten metaData AND tried to create additional model properties that are related.
Your best bet is to add a property that is a navigation type on the constructor.
http://www.breezejs.com/sites/all/apidocs/classes/EntityType.html#method_addProperty
If it were me, I would try it this way (or something similar) inside of the constructor -
myEntity.addProperty({
associatedEntity: {
entityTypeName: "AssociatedEntity", isScalar: true,
associationName: "AssociatedEntity_MyEntitys", foreignKeyNames: ["associatedEntityId"]
}
});
Where myEntity is the name of the current entity, AssociatedEntity would be your navigation property, the associatedEntityId is a property of myEntity that refers to the other entity. Of course to have this be a two-way relationship you would need to add a property to AssociatedEntity as well.
associatedEntity.addProperty({
myEntitys: {
entityTypeName: "MyEntity", isScalar: true,
associationName: "AssociatedEntity_MyEntitys", foreignKeyNames: ["myEntityId"]
}
});

Where does data returned by ember-data 'live'?

ya'll I have a bit of a structural/procedural question for ya.
So I have a pretty simple ember app, trying to use ember-data and I'm just not sure if I'm 'doing it right'. So the user hits my index template, I grab their location coordinates and encode a hash of it (that part works). Then on my server I have a db that stores 'tiles' named after there hash'd coords (if i hit my #/tiles/H1A2S3H4E5D route I get back properly formatted JSON).
What I would like to happen next, if to display each of the returned tiles to the user on the bottom of the first page (like in a partial maybe? if handlebars does that).
I have a DS.Model for the tiles, if I hard code the Hash'd cords into a App.find(H1A2S3H4E5D); I can see my server properly responding to the query. However, I cannot seem to be able to figure out how to access the returned JSON object, or how to display it to the user.
I did watch a few tutorial videos but they all seem to be outdated with the old router.
Mainly I would like to know:
1. Where does the information returned by App.find(); live & how to access it?
2. what is the 'correct' way to structure my templates/views to handle this?
3. how should I pass that id (the hash'd coords) to App.find? as a global variable? or is there a better way?
the biggest problem(to me) seems to be that the id I search by doesn't exist until the user hit the page tho first time. (since its dynamically generated) so I can't just grab it when the page loads.
I can post a fiddle if required, but I'm looking for more of a conceptual/instructional answer rather then some one to just write my code for me
I'm still learning a lot with Ember as well, but this is my understanding. When you follow the guides and the tutorials out there, you'll have something like this:
App.TileController = Ember.ObjectController.extend();
App.TileRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', App.Tile.find(MYHASH));
}
});
What it does is set the special content object to the result. So since we're declaring an object controller, and calling find with a parameter, it knows that a single result is expected. So a view & template that follow the naming convention of Tile will be loaded. And in there you can access properties on the Tile object:
<p>{{lat}}</p><p>{{lng}}</p>
I have to admit that this feels a bit mystical at times. The core to it is all in the naming convention. You need to be pretty specific in how you name all your various controllers, routes, etc. Once that's nailed down, it's a matter of binding what data you want to the controller's content.
1) Aside from the generic answer of "in memory", the .find() calls live where ever you return it to. Generally speaking, this is meant to be set on a 'content' property of a controller.
2) I more or less answered this, but generally speaking you take the name of your route, and base it off that. So for a route TileRoute, you have:
TileController = Ember.ObjectController.extend
Tile = DS.Model.extend
TileView = Ember.View.extend
tile.handlebars
I generally store all my handlebars files in a templates/ folder. If you nest them deeper, just specify the path in your view object:
App.TileView = Ember.View.extend({
templateName: "tiles/show"
});
3) This really depends on your app. Generally speaking its better for the id to be either obtained from the URL, or constructed locally in a function. Since you are encoding a hash, i imagine you're doing this in a function, and then calling find. I do something a bit similar for an Array controller.
I don't know at what point you are generating a hash, so let's say it's onload. You should be able to generate the hash just in the setupController function.
App.TileRoute = Ember.Route.extend({
generateHashBasedOnCoords: function() {
// ...
},
setupController: function(controller) {
var MYHASH = this.generateHashBasedOnCoords();
controller.set('content', App.Tile.find(MYHASH));
}
});
I hope that helps.
I believe that you can make use of the data binding in ember and basically have an array controller for tiles and set the content initially to an empty array. Then we you get back your response do a App.find() and set the content of the tiles controller with the data that is returned. This should update the view through the data binding. (Very high level response)
The data itself is stored in a store that is setup with ember data. You access it with the same method you are using the model methods App.Tile.find() ect. It checks to see if the data that is needed is in the store if so it returns the data otherwise it makes a call to the api to get the data.

Categories