I'm trying to develop an application using the Fixture Adapter with Ember-Data.
When I try and create a new object (based on a model I've defined), it won't work unless I specify the ID.
If I specify the ID and do this:
var person = SD.Person.createRecord({
id: 234,
name: "test"
});
var person.save();
I get:
Error: assertion failed: An adapter cannot assign a new id to a record
that already has an id. had id: 234 and you
tried to update it with 234. This likely happened because your server
returned data in response to a find or update that had a different id
than the one you sent.
Which makes it sound like somehow I'm updating an existing record (I'm not, there's only 2 fixtures for my Person object with ID's of 1 and 2 respectively).
Is Ember trying to save my object twice somehow?
I thought I may have to try and use generateIdForRecord to set the ID, but I can't reference that function no matter what I try.
newBooking.set('id', this.store.generateIdForRecord(this.store, newBooking));
newBooking.set('id', DS.generateIdForRecord(this.store, newBooking));
newBooking.set('id', this.generateIdForRecord(this.store, newBooking));
newBooking.set('id', generateIdForRecord(this.store, newBooking));
TypeError: this.store.generateIdForRecord is not a function
I'm using the latest releases of Ember and Ember-Data (have tried previous releases too). My model is implemented no differently to the TodoMVC tutorial in the Ember guides and in the tutorial nothing fancy needs to be done to manage ID's with the Fixture adapter so I've really no idea what's going on.
How do I create a new Person object (as per my example, just one 'name' field and persist it using Ember-Data's fixture adapter without the aforementioned errors?
In the end, my first code snippet worked fine.
For some reason, I was expecting to see the new object being persisted in the developer console. My models were being listed in a different view so I didn't realize it was actually working as intended.
Related
I'm currently facing a problem with Meteor and React, where i know some partly solutions but they don't work and imo none of them is pointing in the true direction.
The situation:
All is about an fitness app: I have a structure that represents exercises for customers, while each exercise can have a defined number of sets (a set is how often a exercise should be done). Each set has some properties (all the user can manipulate within the font-end).
Now i have the following component structure with some map-functions (state properties are in {}):
Training {customers,exercises,datetime,otherinfos}
- Overview {customers,exercises}
exercises.map():
- Exercise {exercise,customers}
customers.map():
- Customer {exercise,customer}
exercise.sets.map()
Set {exercise, customer, set, valuesofset}
From a UI-perspective (react) this all works without problems.
Now the idea is to have a button "Save" within the Training component. When the button is pressed, I want to save the state of all Set-Components in a "sets" collection (if it has other values than the default placeholder ones) and at the same time save the Training-Component in a "trainings" collection. But the training should also include information about what Sets are integrated (so at least the Set._id should be in the Training-Component state at time of Saving.
Here now my ideas so far:
Create refs from Training all the way down to all Sets and then, when pressing "Save" iterate over all refs and call a "Mongo.insert" from all Sets. Here i have the problem that i cannot return the inserted _id. Of course i could call a different function in each Component from Set all the way back to Training, but imo this is an overflow.
Try to manage the state of all sets within the Training state by calling a nested function. As i have onChangeHandler on the Inputs, this would always call a method in Training and check which one of the Sets was changed and then changes it. I have tried it this way, but it led to a very bad performance.
Create a temp-ID for Training, forward it to to the Sets (using the componentWillReceiveProps method) and when in Set, insert the Set in the database with the temp-ID. Then receive all Sets with temp-ID and use it to add the Training in the database. --> imo very complicated and I don't really want to do a database call if it is not necessary.
So currently i don't know how to solve this problem. The reason i try to separate "sets" and "trainings" is given through the fact, that later on i would like to give information about the last Set right next to the new empty Set whenever one is on the database. Any tips are welcome!
EDIT:
As suggested, there is also the possibility to solve the problem with Session. So therefor i have added the following code to Set:
componentDidMount() {
Tracker.autorun(() => {
Session.set(`set_${this.state.id}`, {
...this.state
});
});
}
My idea was then to iterate over all Session-Keys from Training which start with "set_" - unfortunately there is no function to that holds all Keys.
Second idea was to to use an array as value for a Session-pair. However, it's quite a procedure to handle the update of the reactive Set component (copy array from session, check whether an element is available or not, create a new one or update the existing one).
EDIT2:
I think i got a solution with Session:
Object.getOwnPropertyNames(Session.keys)
did the trick to get all SessionKeys! Thank you for your help!
If you do not want to use Redux or pass parent bound callbacks in the child component, you can try Session to store data at app level which can be accessed(set/get) in any component
https://docs.meteor.com/api/session.html
In your case, you may set values of "Set" in Session and access it in Training. You may also need https://guide.meteor.com/react.html#using-withTracker. Using withTracker will help in doing reactive update of the database on change of any Session variable.
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.
I have a Meteor method that returns all user accounts on my application
returnUsers: function(){
return Meteor.users.find().fetch();
}
I'm using new ReactiveVar to pass the return value of the Meteor method into my template helper:
Template.listViewTemplate.created = function (){
var self = this;
self.myAsyncValue = new ReactiveVar("Waiting for response from serv er...");
Meteor.call('returnUsers', function (err, users) {
if (err)
console.log(err);
else
self.myAsyncValue.set(users);
});
}
Template.listViewTemplate.helpers({
userCollection: function(){
return Template.instance().myAsyncValue.get();
}
});
But when I go to render the users into the view, I get a console error that reads
{{#each}} currently only accepts arrays
When I render without the #each iterator, using
<ul id='usersList'>
{{userCollection}}
</ul>
the output on my web-page accurately reflects the number of users (2), but reads
[object Object],[object Object]
I'm pretty sure that there is some funkiness going on here because I'm using a global Meteor collection (Meteor.users.find().fetch(), as opposed to having defined my own collection), but I'm not sure how to get around it.
I want to display a list of all users so the current user can click another user and share a document with them--not sure how to get around this.
You don't need to use a reactive variable for this. The function at Template.listViewTemplate.created is not container in an autorun, which means: It won't get recomputed.
The best approach for your scenario is: Use a variable to get the status ( loading, loaded, error) and another variable to save the array itself attach to self. Reactivity is cool but you should only use it when needed.
About:
[object Object],[object Object]
This is happening because you're not extracting any value form the object provided nor looping using {{#each}}.
Your solutions for listing users is dangerous and inefficient. You're sending to the client all the fields from the user collection, including login tokens.
The best approach is to create a subscription that send only the necessaries fields like: _id, info.firstName. You should also have some criteria to the list users and use pagination. Consider also a search feature for such purpose.
ReactiveVar doesn't like arrays. You could install the ReactiveArray package which should accomplish exactly what you want.
Update
Based on comment of mper
In the latest versions of Meteor you can put an array in a ReactiveVar.
Tested on
meteor#1.6.0
reactive-var#1.0.11
I have several remarks about your question:
Do not fetch
You don't need .fetch() on your method. When you call find() on collections, such as Meteor.users a cursor is returned. The template (and #each in particular) can iterate through cursors. Cursors are usually better because you don't load the entire collection into memory at once - fetch does.
Meteor collections are reactive
Meteor collections are already reactive, meaning that if they change, they will trigger changes on your templates as well. So, you don't need to use a ReactiveVar to wrap your collection.
Query your local database
You don't need to use a method to get the users and in fact, you shouldn't, because usually you want to make queries to the database stored locally, not make calls to the server. Just call Meteor.users.find() directly in your template helper. You can (and should) control what is available locally through subscriptions.
Use #each with else
You can use the following in your template:
{{#each userCollection}}
...
{{else}}
Waiting for response from server...
{{/each}}
If userCollection is empty, the template will render the else block, just like you wanted.
Summarizing
Delete your method and onCreated with everything inside, change whatever is inside your template helper to only return Meteor.users.find() and use {{#each userCollection}}...{{else}}Waiting for response from server...{{/else}}
By the way
In the latest versions of Meteor you can put an array in a ReactiveVar.
Template.onCreated(function(){}) only gets run once and meteor methods only run once
You need reactivity here.
Collections sre reactive meaning pub/sub.
You need to create a publish function that allows certain users to fetch other users in the database. So all uses with maybe if the currentUser has permission to read all user info. Id limit the fields too.
Is it possible to have multiple dataStore in IndexedDB using angular-localForage?
I tried this:
var $tblStage = $localForage.createInstance({
storeName : 'tblStage', // name of the table
});
but it triggered an error which says:
Error: A localForage instance with the name dbName is already defined.
I read this Question before but, is the only way is working with Raw IndexedDB? Or I missed something in my code? Any Idea?
Yes, only configure when you use.
https://github.com/mozilla/localForage#configuration
But no its possible two instance at same db.
If you intend to use the directive, local-forage, you'll have to copy and configure it.
Just like this https://github.com/ocombe/angular-localForage/blob/master/src/angular-localForage.js#L51, for change the provide,
only change defaultConfig at #L20, and name of angular module directive #L465.
And give more information but the reputation is very low and this leaves hook and my English so bad.
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.