Reputation: 149
I have no idea whats wrong with my code, im reading the book Discover Meteor and building a small app to learn those concepts better:
Template.panelCM.events({
'click .editProductsCol': function(e) {
e.preventDefault();
if (confirm('Edit?')){
var currentProduct = this._id;
var productOptions = {
name: $(e.target).find('[name=productName]').val(),
description: $(e.target).find('[name=productDescription]').val()
};
Products.update(currentProduct, {$set: productOptions}, function(error) {
if (error) {
alert(error.reason);
throwError('Error');
} else {
Router.go('tabPage');
}
});
}},
'click .deleteProductsCol': function(e) {
e.preventDefault();
if (confirm("Delete?")) {
var currentProduct = this._id;
Products.remove(currentProduct);
Router.go('tabPage');
}
}});
The delete part works well, its just the update that I don't figure out whats wrong..
It gives me this error after submitting:
MongoError: '$set' is empty. You must specify a field like so: {$mod: {<field>: ...}}
This is my template:
<template name="panelCM">
{{#each products}}
<div class="col-xs-12 col-sm-6 col-md-6 mainCol">
<img src="../{{image}}"/>
<input type="text" name="productName" id="productName" class="form-control" placeholder="{{name}}">
<textarea name='productDescription' id="productDescription" class="form-control colP" rows="10"
placeholder="{{description}}" style="color: black"></textarea>
<button type="submit" class="btn btn-lg btn-success form-control editProductsCol">Edit</button>
<button type="submit" class="btn btn-lg btn-danger form-control deleteProductsCol">Delete</button>
</div>
{{/each}}</template>
What am I doing wrong, I didn't quite understand that productOptions var I think, if I understood correctly im just creating an object that gets whatever I put on that html element and then I pass it to my Products db to update it, what I don't quite understand is if I need to use an id on my template aswell, I saw it on the Discover Meteor book, but it doesn't make sense since im finding the correct element with the 'name' thing (no idea what thats called).. Also the name and description Im using in the productOptions, should be the same as the one im using on my db right?
Upvotes: 1
Views: 745
Reputation: 618
$.find looks to the descendants of the DOM element it's called on. You're calling it on the edit button, which has no children. That means it finds nothing, and the call to .val()
returns undefined
. MongoDB's complaining that you're setting both fields to undefined
, which means pretty much nothing. Try something like this instead:
'click .editProductsCol': function(e, template) {
e.preventDefault();
if (confirm('Edit?')) {
var productOptions = {
name: template.$('[name=productName]').val(),
description: template.$('[name=productDescription]').val()
};
Products.update(this._id, {$set: productOptions}, function(error) {
if (error) {
alert(error.reason);
throwError('Error');
} else {
Router.go('tabPage');
}
});
}
},
Let's go through the code. Meteor binds this
inside an event handler to your model, so this._id
(that you assigned to the currentProduct
variable) gets the id of the document you want to update.
So, now you now what document (MongoDB items are called documents) to update. How to do it and what to set it to? Well, we want to update based on the form data. The second parameter passed to the event handlers is the template
instance, which contains a $ property that queries the DOM only inside the template's context. That's where we get our form values.
Now, we just have to call the update
method on the Meteor.collection
and we're gold. As you can see from the docs, it takes the _id
as a selector, a modifier object and a callback. Your modifier is the object with the $set
property. It tells MongoDB to keep the document as it is, just adding/replacing the fields we're indicating (instead of replacing the whole document).
One more thing, if there's no specific reason to do otherwise, I suggest you replace the placeholder
attribute on your input elements with value
s. The placeholder is just a visual cue, it means nothing to the form content itself.
<input type="text" name="productName" id="productName" class="form-control" value="{{name}}" placeholder="Enter the name">
<textarea name='productDescription' id="productDescription" class="form-control colP" rows="10" value="{{description}}" style="color: black" placeholder="Enter a description"></textarea>
Upvotes: 1