Meteor Router data function being called twice - javascript

I have a router data function that calls a Meteor method to insert a new document into a collection. I noticed that the document was being inserted twice and then I noticed that the data function itself is called twice every time the route is visited. I can't figure out why this is happening.
Router.route('/myurl',{
name: 'myurl',
path: '/myurl',
data: function () {
console.log('dupe?');
// the data function is an example where this.params is available
// we can access params using this.params
// see the below paths that would match this route
var params = this.params;
// we can access query string params using this.params.query
var post = this.params.query;
// query params are added to the 'query' object on this.params.
// given a browser path of: '/?task_name=abcd1234
// this.params.query.task_name => 'abcd1234'
if(this.ready()){
Meteor.call('points.add', post, function(error, result){
if(error)
{
Session.set("postResponse", "failed");
}
else
{
Session.set("postResponse", "success");
}
});
return {_message: Session.get("postResponse")};
}
}
});

I was able to fix this by moving everything under data to a Router.onRun hook.

Related

Getting x from remote sources and mirroring on to a list

Currently I have this, if with the full app it will create a post with my chosen parameters, however I am very new with vue.js, My aim is to be able to have a text file of such (or other way of storing (json etc)) the values, and then having the js script iterate through the file and display as cards, so for example in the file I would have
"Mark", "http://google.com", "5556", "image"
Or of course using json or similar, I'm up to what ever but my problem is, I don't know how to get values from a remote source and mirror it on to the document, can anyone help?, for clarity here's the snippet of code that I'm using
var app = new Vue({
el: '#app',
data: {
keyword: '',
postList: [
new Post(
'Name',
'Link',
'UID',
'Image'),
]
},
});
-- EDIT --
I'd like to thank the user Justin MacArthur for his quick answer, if you or anyone else doesn't mind answering another one of my painfully incompetent questions. This is the function that adds the cards in a nutshell
var Post = function Post(title, link, author, img) {
_classCallCheck(this, Post);
this.title = title;
this.link = link;
this.author = author;
this.img = img;
};
I can now get the data from the text file, meaning I could do, and assuming I have response defined (that being the http request) it'll output the contents of the file, how would I do this for multiple cards- as, as one would guess having a new URL for each variable in each set of four in each card is not just tedious but very inefficient.
new Post(
response.data,
)
The solution you're looking for is any of the AJAX libraries available. Vue used to promote vue-resource though it recently retired that support in favor of Axios
You can follow the instructions on the github page to install it in your app and the usage is very simple.
// Perform a Get on a file/route
axios.get(
'url.to.resource/path',
{
params: {
ID: 12345
}
}
).then(
// Successful response received
function (response) {
console.log(response);
}
).catch(
// Error returned by the server
function (error) {
console.log(error);
}
);
// Perform a Post on a file/route
// Posts don't need the 'params' object as the second argument is sent as the request body
axios.post(
'url.to.resource/path',
{
ID: 12345
}
).then(
// Successful response received
function (response) {
console.log(response);
}
).catch(
// Error returned by the server
function (error) {
console.log(error);
}
);
Obviously in the catch handler you'd have your error handing code, either an alert or message appearing on the page. In the success you could have something along the lines of this.postList.push(new Post(response.data.name, response.data.link, response.data.uid, response.data.image));
To make it even easier you can assign axios to the vue prototype like this:
Vue.prototype.$http = axios
and make use of it using the local vm instance
this.$http.post("url", { data }).then(...);
EDIT:
For your multi-signature function edit it's best to use the arguments keyword. In Javascript the engine defines an arguments array containing the parameters passed to the function.
var Post = function Post(title, link, author, img) {
_classCallCheck(this, Post);
if(arguments.length == 1) {
this.title = title.title;
this.link = title.link;
this.author = title.author;
this.img = title.img;
} else {
this.title = title;
this.link = link;
this.author = author;
this.img = img;
}
};
Be careful not to mutate the arguments list as it's a reference list to the parameters themselves so you can overwrite your variables easily without knowing it.

Easiest way to get Json / Collection through Meteor Iron Router

I'm creating a set of routes, for example
/ - should render home page template
/items - should items page template
/items/weeARXpqqTFQRg275 - should return item from MongoDB with given _id
This is example of what I'm trying to achieve
Router.route('items/:_id', function () {
var item = return myItems.find(:_id);
this.render(item);
});
[update - solved]
solved this by using Router.map on server side instead of Router.route
Router.map(function () {
this.route('post', {
path: 'items/:_id',
where: 'server',
action: function(){
var id = this.params._id;
var json = myItems.findOne({_id: id});
this.response.setHeader('Content-Type', 'application/json');
this.response.end(JSON.stringify(json, null, 2));
}
});
});
There are several problems with your code.
First, it seems you want to get the _id parameter from the url and don't know how. It's stored on this.params, so it's this.params._id.
Second, the first parameter you should send to find is a MongoDB query that in your case would be { _id: this.params._id }.
Third, that's not how you render something in Iron Router. The string parameter on the render method is the name of the template you want to render, not the item.
Assuming that myItems is a valid collection and your template is called showItem, your code should be something like:
Router.route('items/:_id', {
name: 'showItem',
data: function () {
return myItems.find({ _id: this.params._id });
}
});
Try something like this:
Router.map(function () {
this.route('items/:myItemId', {
data: function(){
return myItems.findOne({_id: this.params.myItemId});
}
});
});
good luck!

Backbone fetch success and error function issue

I've a fetch method on a collection. The callback function success and error is never called but the fetch happens correctly and fill the collection. It seems very strange.
var TweetsCollection= new Tweets();
TweetsCollection.fetch({
success:function (tweets){<---never called
alert("ok");
},
error:function(c){<---never called
alert("ko");
}
});
console.log(TweetsCollection);<---- collection correctly filled
and this is the fetch methof od TweetsCollection:
fetch: function(options) {
var collection = this;
var params = {
user_id: this.query,
page:this.page
};
cb.__call(
"statuses_userTimeline",
params,
function (reply) {
// console.log(reply);
collection.reset(reply);
// return reply;
}
);
}
You don't have to override the fetch method.
If you want to add extra logic to the sync process, you override the sync method.

ExpressJS why is my GET method called after my DELETE method?

In my express app, when the DELETE method below is called, the GET method is immediately called after and it's giving me an error in my angular code that says it is expected an object but got an array.
Why is my GET method being called when i'm explicitly doing res.send(204); in my DELETE method and how can I fix this?
Server console:
DELETE /notes/5357ff1d91340db03d000001 204 4ms
GET /notes 200 2ms - 2b
Express Note route
exports.get = function (db) {
return function (req, res) {
var collection = db.get('notes');
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
};
};
exports.delete = function(db) {
return function(req, res) {
var note_id = req.params.id;
var collection = db.get('notes');
collection.remove(
{ _id: note_id },
function(err, doc) {
// If it failed, return error
if (err) {
res.send("There was a problem deleting that note from the database.");
} else {
console.log('were in delete success');
res.send(204);
}
}
);
}
}
app.js
var note = require('./routes/note.js');
app.get('/notes', note.get(db));
app.post('/notes', note.create(db));
app.put('/notes/:id', note.update(db));
app.delete('/notes/:id', note.delete(db));
angularjs controller
$scope.delete = function(note_id) {
var note = noteService.get();
note.$delete({id: note_id});
}
angularjs noteService
angular.module('express_example').factory('noteService',function($resource, SETTINGS) {
return $resource(SETTINGS.base + '/notes/:id', { id: '#id' },
{
//query: { method: 'GET', isArray: true },
//create: { method: 'POST', isArray: true },
update: { method: 'PUT' }
//delete: { method: 'DELETE', isArray: true }
});
});
** UPDATE **
To help paint the picture, here's the angular error i'm getting:
Error: [$resource:badcfg] Error in resource configuration. Expected response to contain an object but got an array http://errors.angularjs.org/1.2.16/$resource/badcfg?p0=object&p1=array
I'm assuming that i'm getting this error because my delete method is calling my get method (somehow) and the get method returns the entire collection.
Server side
You're removing an element from a collection in your delete function. This is done asynchronously and calling your callback when it's finished.
During this time, other requests are executed, this is why your GET request is executed before your DELETE request is finished.
The same happens in your get function, you're trying to find an element from a collection and this function is too asynchronous.
But this is server side only and it is fine, it should work this way, your problem is located client side.
Client side
If you want to delete your note after you got it, you will have to use a callback function in your angular controller which will be called only when you got your note (if you need help on that, show us your noteService angular code).
This is some basic javascript understanding problem, actions are often made asynchronously and you need callbacks to have an execution chain.
Maybe try doing something like this:
$scope.delete = function(note_id) {
var note = noteService.get({ id: note_id }, function()
{
note.$delete();
});
}
Your code doesn't make sense though, why is there a get in the $scope.delete? Why not do as simply as following:
$scope.delete = function(note_id) {
noteService.delete({ id: note_id });
}
Error
I think you get this error because of what your server sends in your exports.delete function. You're sending a string or no content at all when angular expects an object (a REST API never sends strings). You should send something like that:
res.send({
results: [],
errors: [
"Your error"
]
});

Ember data doesn't append parameters to the query

Ember data just doesn't append parameters to the query. I have a tags route like this
example
App.TagsRoute = Ember.Route.extend({
model: function(params) {
var tag = params.tag_name;
var entries = this.store.find('entry', {tags: tag});
return entries;
}
});
but this keeps making the same request as this.store.find('entry').
i'm doing it wrong?
Edit:
My router looks like this:
App.Router.map(function(){
this.resource('entries', function(){
this.resource('entry', { path: '/entry/:entry_id/:entry_title' });
});
this.route('tags', { path: '/t/:tag_name' });
});
when i request (for example) localhost:8888/#/t/tag
the value of params.tag_name is 'tag'
edit2:
My REST adapter
App.ApplicationAdapter = DS.RESTAdapter.extend({
bulkCommit: false,
buildURL: function(record, suffix) {
var s = this._super(record, suffix);
return s + ".json";
},
findQuery: function(store, type, query) {
var url = this.buildURL(type.typeKey),
proc = 'GET',
obj = { data: query },
theFinalQuery = url + "?" + $.param(query);
console.log(url); // this is the base url
console.log(proc); // this is the procedure
console.log(obj); // an object sent down to attach to the ajax request
console.log(theFinalQuery); // what the query looks like
// use the default rest adapter implementation
return this._super(store, type, query);
}
});
edit3:
making some changes to my TagsRoute object i get the next output:
App.TagsRoute = Ember.Route.extend({
model: function(params) {
var tag = params.tag_name;
var query = {tags: tag};
console.log(query);
var entries = this.store.find('entry', query);
return entries;
}
});
console output when i request localhost:8888/#/t/tag
Object {tags: "tag"}
(host url) + api/v1/entries.json
GET
Object {data: Object}
(host url) + api/v1/entries.json?tags=tag
Class {type: function, query: Object, store: Class, isLoaded: true, meta: Object…}
Ember data is attaching GET parameters. i think my error maybe is the requested url, it should be something like this
(host url) + api/v1/tags/:tag_name.json
instead of
(host url) + api/v1/entries.json?tags=:tag_name
SOLUTION
the build of ember-data (ember-data 1.0.0-beta.3-16-g2205566) was broken. When i changed the script src to builds.emberjs.com.s3.amazonaws.com/canary/daily/20131018/ember-data.js everything worked perfectly.
the proper way to add GET parameters is:
var query = {param: value};
var array = this.store.find('model', query);
thanks for your help
You are doing everything correct, are you sure the request being sent back to the server doesn't contain the query?
The full query isn't created until JQuery makes the call.
Did you look at the network tab in chrome (or whatever browser you are using) to see what it's sending back.
Watch the console in the jsbin below, it shows what happens when you use find with an object (for querying):
App.MyAdapter = DS.RESTAdapter.extend({
findQuery: function(store, type, query) {
var url = this.buildURL(type.typeKey),
proc = 'GET',
obj = { data: query },
theFinalQuery = url + "?" + $.param(query);
console.log(url); // this is the base url
console.log(proc); // this is the procedure
console.log(obj); // an object sent down to attach to the ajax request
console.log(theFinalQuery); // what the query looks like
// use the default rest adapter implementation
return this._super(store, type, query);
},
});
http://emberjs.jsbin.com/AyaVakE/1/edit
Additional questions:
hitting: http://localhost:8888/#/t/tag fires the tags route, sending in 'tag' to the tag_name. Your model hook is correct. Where are you seeing that the request is the same?
Additionally, you mentioned store.find('entries) and store.find('entry'). I know they handle pluralization of most things, but you should make sure those end up being the same endpoint /api/entries.
The RESTAdapter sends your query object to the jQuery.ajax() method by tacking it onto the data property of the settings object. (See here for info on what is done with the settings object.)
It looks like maybe the tag name is not defined. Try to make sure that the tag_name parameter is properly coming from your route.

Categories

Resources