I have a REST API consumed by an ember app.
Here is the .hbs which lists a model. I can give new elements with the "save" action, and every item has also a "delete" action.
{{ input value=name }}
{{ input value=value }}
<button {{ action "save" this }}>Save</button>
<table class="table">
{{#each item in model}}
<tr><td>{{item.name}}</td><td>{{float2 item.value}}</td><td><button {{ action "delete" item}}>delete</button></td></tr>
{{/each}}
</table>
So far works everything fine. The problem if i insert (save) a new element, i cant "delete" it, it has id:null, and the request to the api has no id at the end of the URL. (although on the client side the item will be removed from the list)
here is the controller's actions:
actions: {
save: function (record) {
var vat = this.store.createRecord('vat',{
name: this.get('name'),
value: parseFloat(this.get('value'))
});
vat.save();
},
delete: function(record){
console.log(record);
record.deleteRecord();
record.save();;
}
}
My guess is after the insert the API doesnt have the correct response, and ember-data doesnt know the new item's id. (maybe im wrong) what respons (JSON structure) expects the RESTAdapter, with which status code?
In your case the response from server should have 200 or 201 status code and the body should look like this
{
"vat": {
"id": 1,
"name": "Name",
"value": 10.5
}
}
You can also override normalize function in RESTAdapter to adjust the format of server response.
Related
I want to update only the name field, the problem with the code I have is that if I update a document, all the mongo documents are updated.
As I update a document in specific, I must admit that I am new to this mongo so any help I thank you.
Client
updatename.html
<template name="updatename">
<form class="editor-container">
<input class=“save” type="text" id="card" value=“{{name}}”>
<button type="button" class=“save” id="save">save</button>
</form>
</template>
updatename.js
Template.updatename.events({
'click .save’: function (e, t) {
e.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('name.update',name);
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
'name.update'( name) {
Name.update({
Name.update({},{ $set: { nam: name }},{multi:true})
});
}
});
I recommend few improvisations over your Meteor code.
Atleast use Title Case/ CamelCase for better readability of the template name and Meteor Methods for other developer.
use submit .formClassName instead of using click .save, also specifiy parameter name with sincerity like function (event, template)
When you updating document for logged user and not other user, as dmayo mentioned in the code use Name.update({_id: Meteor.userId()},{ $set: {nam: name}}), but there is no sense of specifying { multi: true } when you know that there is going to be only 1 record when you are updating. You can use { multi: true } when you desire to impact many records based on criteria that are definitely going to return more than 1 record.
use check(name, String) in Meteor.method call to ensure what you are sending to the server is eligible for further operations.
Use aldeed autoforms when you know there is no out of the box implementation and is going to be simple.
Below is the improvised code for better readability and up to standards
Client
update-name.html
<template name="UpdateName">
<form class="editorContainerForm">
<input type="text" id="card" value=“{{name}}”>
<button type="submit">Save</button>
</form>
</template>
update-name.js
Template.UpdateName.events({
'submit .editorContainerForm’: function (event, template) {
event.preventDefault();
FlowRouter.watchPathChange();
var name = FlowRouter.current().params._id;
var name = $('#card').val();
Meteor.call('updateName',name, function(error, response){
if(error){
// Show some BERT ERROR message for better user experience
// use "meteor add themeteorchef:bert" to add package
} else {
// Show some BERT SUCCESS message for better user experience
});
FlowRouter.go('/');
}
});
Server
name.js
Meteor.methods({
updateName( name ) {
check(name, String);
Name.update({ _id: Meteor.userId },{ $set: { name: name }});
// Use below code only if you know there can be multiple records for same ID
// Name.update({ _id: Meteor.userId },{ $set: { name: name }}, { multi: true });
}
});
In your name.js file (on the server) your mongo query is empty, so when mongo queries your database, it matches all of the documents/records.
Name.update(query, changes, options)
That is the format per the mongo docs. You need to have a unique identifier. Your form is saving a "name", and that's what you are passing to the Meteor.method, but you're not telling the method who's changing their name. If the user is logged in, then you can just use the meteor unique id Meteor.userId()
Name.update({_id: Meteor.userId()},{ $set: {nam: name}},{multi:true})
Also, your option multi:true says to update any and all documents that match the query. If in your original method as written, you had multi:false (the default) then only one document would have been updated (but probably not the one you wanted as the first match would have been updated because of your empty query field.
Mongo docs: https://docs.mongodb.com/manual/reference/method/db.collection.update/
Metor docs: https://docs.meteor.com/api/collections.html#Mongo-Collection-update
I'm working on an app in Meteor, let's call it meetups. I've already done basic crud and now I'm stucked with request action when a user sends a request for invite for a meetup (I use accounts-password package to handle auth, if it means anything). I want to show meetup's owner which users would like to visit this meetup, so it's how I designed it:
I created a 'Join' button in my template and it works perfectly when I make an event in my controller like this:
'click .join': function(event) {
var params = {
user: Meteor.userId(),
username: Meteor.user().username
}
toastr.success('You've send a request');
Router.go('/meetups');
}
Since I handle this events fetching user's params, it's very easy to show his username, I do it like this:
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
I don't want to just show this user, I want to let meetup's owner also manage requests (that's why I created two buttons). Basically, it's just a simple crud, isn't it? That's why I created a new Mongo collection called 'Guests' and my 'invite event now looks like this:
'click .join': function(event) {
var params = {
user: Meteor.userId(),
username: Meteor.user().username
}
Meteor.call('join', params);
toastr.success('Ok');
Router.go('/meetups');
}
In case I use call function, I have a method to handle it:
Meteor.methods({
'join': function (params) {
Guests.insert(params);
}
});
I also created anothe template called guests:
<template name="guests">
{{#each guests}}
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
{{/each}}
</template>
and included it in my meetups template like this: {{> guests}}.
As you can understand since that I see no usernames. I used an iteration through guests collection and try to fetch username because it worked just fine withound defining a separate collection.
So my question is how the heck can I push specific users (in my case those who clicked join button) and show their usernames? Any help would be appreciate.
<template name="guests">
{{#each guests}}
<p>{{username}} sent a request to join your meetup</p> <button class="btn-primary btn-xs yes">Ok</button> <button class="btn-danger btn-xs no">No</button>
{{/each}}
</template>
How about add guests helper in guests template?
You didn't define it.
Template.guests.helpers({
guests: function () {
return Guests.find();
}
});
Passing values dynamically through templates in meteor fails, whereas doing so statically succeeds. What am I doing wrong? The set-up is as follows
I have the following 2 templates set-up in Meteor
<template name="search">
{{#each cards}}
{{>card}}
{{/each}}
<template name="card">
<div class="card">
{{docName}}
</div>
</template>
Passing values to this like this works perfectly
if (Meteor.isClient) {
Template.search.helpers({
cards: [
{docName: "Dr. Maga" },
{docName: "Dr. Macha" },
]
});
}
However, passing the same values dyamically like this fails
Cards = new Mongo.Collection("cards");
if (Meteor.isClient) {
Template.search.helpers({
cards: function() {
return Cards.find({});
}
});
}
There is data in the mongo collection "Cards". I insert it after the app starts by using
db.Cards.insert({ docName: "Hello world!", createdAt: new Date() });
and verify it using the following command
db.Cards.find()
which returns
{ "_id" : ObjectId("558b0a1394990bf66c75775d"), "docName" : "Hello world!", "createdAt" : ISODate("2015-06-24T19:50:42.996Z") }
What am I doing wrong?
The error was that the Cards collection was defined on the client side only. (Under the Meteor.isClient() Code block).
This means that meteor was trying to read from the Server, couldn't find the item coz it wasn't defined in the server side, and failed.
Solution is to define it in the "both" folder so that both server and client can access the collection.
http://docs.meteor.com/#/basic/filestructure
Of course, don't forget to publish and subscribe to the collection.
i have an "back end" application which write in MongoDb (in database i have _id: with ObjectId("13f6ea...002")) i use meteor app to show information. Everything was good i displays list of information with {{#each}}. But when i wanted show one element with '_Id' nothing works.
I read this issue and adapt my code to get right root, But i can't display anything on the page. I tried to write Template helpers but it didn't helped
Db record:
{
_id: ObjectId("13f6ea...002"),
url: "foo",
title: "bar",
published: "2014-08-22 03:26:21 UTC",
image: "foo.jpg",
summary: "foo ",
categories: [
"F",
"B"
],
...
}
Route:
this.route('news', {
path: '/news/:_id',
template: 'news',
waitOn: function () {
var id = this._id;
Meteor.subscribe('news', id);
},
data: function() {
var id = this.params._id;
return News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
},
action : function () {this.render();},
});
Publish
Meteor.publish('news', function(id) {
return News.find({_id: id});
});
Template which redirect to unique post
<h4>{{title}}</h4>
And template is just {{news}}
How can i fix this?
UPDATE
My solutions to fix that:
router.js
waitOn: function () {
var id = this._id;
Meteor.subscribe('News', id);
},
data: function() {
return News.findOne(new Meteor.Collection.ObjectID(this.params._id));
},
and in template
<a href="news/{{_id._str}}">
Navigate to the appropriate url in your browser (i.e. localhost:3000/news/[_id]), open the console and enter:
Router.current().data()
That will show you the data context of the current route. Either it returns nothing, in which case there is a fundamental problem with your News.findOne query as it's returning nothing, or (more likely) it returns the required document.
In the latter case, as far as I can see there is no news property within that document, which is why it isn't rendering anything. If you change {{news}} to {{url}} or {{summary}} I would imagine it would render the requested property.
If by {{news}} you're trying to render the entire document, then (aside from the fact that it will render as something like [Object]) you need to make news a property of the object returned by your data function:
return {
news: News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
};
Getting Document with _id :
In the .js file under events, Say on click event and Collection EventList :-
'Submit form' : function () {
var id = this._id;
return EventList.find({_id : id}).fetch();
}
This would return the object for the id. In my Case, I am displaying a field for all documents in Collection. User selects a record and clicks Submit, which fetches all Document fields and displays to the User
I have the following user object returned from a REST Api:
{
user: {
id: 3451,
name: "First Last",
favorites: {
designs: {
name: "Design 1",
url: "Url 1"
},
typo: {
name: "Typo 1",
url: "Url 2"
},
games: {
name: "Game 1",
url: "Url 3"
}
}
}
}
I got this response from the url /users/3451.
And here's my User model:
App.User = DS.Model.extend({
name: DS.attr('string'),
favorites: DS.attr(), // ??? What to put here?
});
I have no problem displaying the {{name}}. But in the favorites, I don't know.
I tried using {{#each}}
{{#each favorites}}
{{#key}} - {{name}}
{{/each}}
but no luck.It throws an error: Error: Assertion Failed: The value that #each loops over must be an Array. You passed [object Object]
What is the correct way of handling these kinds of complex objects in EmberJS? Please help.
I think the error is pretty self explanatory: you need to be looping over an array, not an object. Here's how I would convert that object to an array, while saving the key (put this in your model):
favoritesArray: function() {
var favorites = this.get('favorites');
return Em.keys(favorites).map(function(key) {
return {
key: key,
data: favorites[key]
};
});
}.property('favorites.#each.{name,url}')
Then, in your template:
{{#each favoritesArray}}
{{key}} - {{data.name}}
{{/each}}
That would be the easiest way to do it. But if you're looking for a slightly better way (in my opinion), you can user a type transform to convert the data to the format you need at the time of (de)serialization.
EDIT: Just for a bit of background info, I believe the reason that Ember.js doesn't support iterating over objects is because there is no way to bind to the object keys. Ember.js knows to update a bound helper when the dependent key observers are fired, but as far as I know, there is no way to observe the keys of an object. Something like this might be possible using an Map or similar, but I don't think that it's built in functionality.