Pass variable to template callback - javascript

Recently I started getting familiar with meteor platform, and I stumbled on dilemma:
Is there a way to pass variables to Template.rendered, Template.created callbacks.
Let's say I have route
Router.route('/profile/:_id', {
name: 'profile'
});
and I want to somehow to pass that _id variable to Template.rendered callback:
Template.profile.rendered = function () {
//how can I get "_id" in here?
};
Is this possible? If so how can I do it?

Usually when you declare a route, you also specify a data context to provide to the template that will be rendered :
Router.route('/profile/:_id', {
name: 'profile',
data: function(){
return Meteor.users.findOne(this.params._id);
}
});
This way you can reference the user _id coming from the current data context assigned to the profile template like this :
Template.profile.rendered = function () {
console.log(this.data._id);
};

Related

Vue JS 2 data manipulation

I have an instance of mounted in Vue, where I'm trying to set a date picker having the starting date depends on a data fed by an ajax response. Let's say this data property is named start_date. I run my ajax request via the created instance in Vue.
It's a little weird when I tried to console log vm.myObject, it shows the correct value start_date property coming from the ajax response. However, whenever I access the specific property via vm.myObject.start_date it will show you the default one I've created for data binding. My code structure below:
<script>
export default {
mounted() {
const vm = this;
console.log(vm.myObject); // this will show the data from ajax response
console.log(vm.myObject.start_date); //this will show the default value I set which si the 2017-10-25
},
created() {
const self = this;
$.ajax({
url: ApiRoutes.paths.GetDealData,
data: { id: 1 },
success: function(res) {
self.myObject.start_date = res.start_date;
}
});
},
data() {
return {
myObject: { start_date: "2017-10-25" }
};
}
};
</script>
I'm very new to Vue JS, so I'm currently having a hard time handling the data in the component via ajax request. I've already tried all the instances included beforeCreate, beforeMount but it didn't fix my issue still. How can I understand this kind of behavior?
Your code can't really work the way you described in your answer.
you are doing asynchronous operation (ajax call) and try to print the values right after synchronous operation? nope.
If you want to console.log(response) , you can do it in your callback function.
If you want to print the value on the page, but show nothing until the value is fetched (asynchronous operation), you can define on your data an attribute that signal if the fectching process is finished or not. and toggle it inside your callback.
I have edited the code to show how to declare the date-picker (have to be declared from the template side.
You have to pass the start_date as a props (I assume the prop name for the date-picker is start-date). when the ajax request is finished, the reactivity of vue will take care of re-rendering of the date-picker
<template>
<div>
<datePicker :start-date="myObject.start_date" />
</div>
</template>
<script>
export default {
created() {
$.ajax({
url: ApiRoutes.paths.GetDealData,
data: { id: 1 },
success: function(res) {
self.myObject.start_date = res.start_date;
self.isFetchedFinished = true
}
});
},
data() {
return {
startDate: ''
};
}
};
</script>
The reason is console.log() working before AJAX response is returned, so console.log(vm.myObject.start_date) prints unchanging string with initial value. However, console.log(vm.myObject) prints your object, which then changes, and you can see actual property value in browser console.
Example:
var obj = { "name": "oldName" };
console.log(obj);
obj.name = "newName";
If you want a "frozen" version of your object, you can create a copy for logging:
console.log(Object.assign({}, vm.myObject));
Also, instead self.myObject.start_date = res.start_date; you probably want to use this.$set(this.myObject, 'start_date', res.start_date); for change tracking.

Can't extract data from $resource (consuming rest webservice)

I'm trying to consume a REST webservice, responding with a JSON String containing a fairly "complex" schema.
I created a model that contains every fields sent by the webservice.
Here are the relevant codes that should be a problem :
public getUser(user_id: number): PlanDeCharge.Modeles.User {
var toto;
this.UserRest.get({ user_id: user_id }, function(){}, function(err){
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
}).$promise.then(function(data){
toto = data;
});
return toto;
}
-
this.userConnecte = this.gestionUserService.getUser(759);
-
export function userRest($resource: ng.resource.IResourceService, $cookies: ng.cookies.ICookiesService): PlanDeCharge.Modeles.IUserResource {
this.key = $cookies.get("encodedKey");
var urlService: string = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return <PlanDeCharge.Modeles.IUserResource> $resource(urlService, {user_id: "#user_id"}, {
get:{
headers:{"key" : this.key}
}
});
}
app.factory("UserRest", ["$resource", "$cookies", userRest]);
I did a lot of modifications, trying to fix the call without success... The request actually get a response containing the JSON string, but I can't put it inside an object to be use (like user['id'] = 2)
Thanks in advance
I deleted the last post and made this new one, the first one wasn't clear enough and people were confused
When working with promises you should let Angular handle the resolvement.
Am I right, if you are actually using AngularJS 1 and not ng2 as the question is tagged? The syntax is ng1 anyways.
Some notes on the getUser method. Return the reference created by $resource instead of creating one your self. Further more, use the fat-arrow syntax on the callbacks to bind this to the proper context. See this article for more on this.
To remove even more code use TypeScripts object initialization and init the user id object with just { user_id }. This creates a JavaScript object with a property user_id with the value of user_id.
public getUser(user_id: number): SomeModel {
return this.UserRest
.get({ user_id }, () => { }, () => {
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
});
}
In your component or controller access
this.userConnecte = this.gestionUserService.getUser(759);
Lastly, the factory/service.
Use the fact that $resource is generic and set your variables as constants when not changed.
export function userRest(
$resource: ng.resource.IResourceService,
$cookies: ng.cookies.ICookiesService
): ng.resource.IResourceClass<PlanDeCharge.Modeles.IUserResource> {
this.key = $cookies.get("encodedKey");
const urlService = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return $resource<PlanDeCharge.Modeles.IUserResource>(urlService, { user_id: "#user_id" }, {
get: {
headers: { "key": this.key }
}
});
}
This should fix your problems and make to code more readable. :)

Meteor Iron Router : custom id route

Having a bit of trouble with iron router and passing in a custom id from a collection.
Some context: I have a collection of "groups" in which they all have their own special id other than the default _id that is auto generated. I am trying to make a route that is like
" localhost:3000/groups/:groupid "
so each group will have its own rendered template with the groups information.
HTML :
<template name="Group">
<h1>Group: {{groupName}}</h1>
</template>
CLIENTSIDE:
grabbing a groupid from a session...
I tested this and it works so its not an issue with grabbing it from the session but rather with the router
var groupid = Session.get('groupID');
Router.go('/groups/:_id',{_id: groupid})
ROUTER:
Router.route('/groups/:_id', function () {
this.render('Group', {
data: function () {
return GroupsList.findOne({_id: this.params._id});
}
});
});
This will render a route with groupid as the params instead of the actual number
UPDATE:
CLIENT
Router.go('/groups/'+ groupid);
ROUTER
Router.route('/groups/:groupid', function () {
this.render('Group', {
data: function () {
console.log(this.params.groupid)
console.log(GroupsList.findOne({groupID: this.params.groupid}))
return GroupsList.findOne({groupID: this.params.groupid});
}
});
});
This seems to get the route to work but it wont render the groupname in the template
From the Iron Router Guide:
Now that we're using named routes in Router.go you can also pass a
parameters object, query and hash fragment options.
Router.go('post.show', {_id: 1}, {query: 'q=s', hash: 'hashFrag'});
However when you call Router.go, you are not passing a route name, but a url.
Try this:
Router.go('/groups/' + groupid);
Router.route('/groups/:_id', function () {
this.render('Group', {
data: function () {
return GroupsList.findOne({groupid: this.params._id});
}
});
});
On a side note from the answer just in case anyone else has this issue , I actually figured out there was an issue in the data type of the "this.params._id" , it seems it was coming up as a data type that was not a string or number and therefore could not be successfully used in the findOne method. In the end I just had to parseInt and this was the solution at the end :
Router.go('/groups/'+ groupid);
Router.route('/groups/:groupid', function () {
this.render('Group', {
data: function () {
var id = parseInt(this.params.groupid)
return GroupsList.findOne({groupID: id});
}
});
});

Meteor collection always returns undefined on client

Im new to meteor and have been trying to learn the framework via the discover meteor book. Im having a few issue understanding what exactly is going on in my application (found here https://github.com/Themitchell/Sound-wav.es).
Essentially, my understanding is that on my server side I allow publications for certain collections which take arguments from my client side subscribe calls. For this part on my server i have this in my server/publications.js file:
Meteor.publish('studios', function (options) {
return Studios.find({
userId: this.userId
}, options);
});
Meteor.publish('studio', function (id) {
return id && Studios.find({
userId: this.userId,
_id: id
});
});
Next we would need a controller to handle the routing and deal with waiting for any subscriptions required, then, once the subscriptions are ready (hence the waitOn) go and render the template providing the data function as a reactive data source for the templates.
So I then set up my 2 routes for indexing studios and showing one studio using iron router and 'Controllers' as follows:
StudiosIndexController = RouteController.extend({
template: 'studiosIndex',
increment: 20,
limit: function () {
return parseInt(this.params.studiosLimit) || this.increment;
},
findOptions: function () {
return {
sort: this.sort,
limit: this.limit()
};
},
waitOn: function () {
return Meteor.subscribe('studios', this.findOptions());
},
studios: function () {
return Studios.find({}, this.findOptions());
},
data: function () {
return {
studios: this.studios()
};
}
});
ShowStudioController = RouteController.extend({
template: 'showStudio',
waitOn: function () {
return Meteor.subscribe('studio', this.params._id);
},
studio: function () {
return Studios.findOne(this.params._id);
},
data: function () {
return {
studio: this.studio()
};
}
});
Router.map(function () {
this.route('studiosIndex', {
path: '/',
controller: StudiosIndexController
});
this.route('showStudio', {
path: '/studios/:_id',
controller: ShowStudioController
});
});
Now this is great and works fine when displaying my index page. I get a list of collections which is reactive and the as i introduce new studios to the collection i see them get created on the server and on the client respectively. However in my show view when the view is rendered the data always seems to be empty. On dropping into my show controller's data function with a debugger I tried querying the Studios and this always returns undefined even when i try to fetch everything possible. Oddly I know that my publications are logging the correct id for a studio (using console.log). It seems that i get all the correct data up until the routing on the client side. The parameter ids are all correct but a find() call on studios always returns nothing. Am I missing something obvious here.
Its also worth noting i deleted my helpers for 'studios' and 'studio' in views/studios/index.js and views/studios/show.js respectively as my understanding is that this is what im doing with studios and studio in the controller. These helpers are now defined at the controller level and passsed to the reactive 'data' function. IS this correct?
TL;DR
With the code above my index action works however my show action fails where the data function always returns undefined and in fact on the show page i cannot get access to any of my studio information (Studios.find({}).count() always returns 0). I'm unsure how the 2 routes differ. Can anyone spot the issue?
Edit: Its also worth noting having looked through some of the iron router issues on github i have tried using this.ready(). The first time the route is run i hit data and this is false but then even wrapping my data helpers to wait for this.ready() gets an undefined return value when this.ready() returns true.
Extra Notes
Im running meteor 0.8.0 with latest 0.7.0 release of iron router and collection2 with simple schema, just in case you are interested / require this info.
EDIT: Possible solution
So having fiddled around it seems like my helpers are the issue. By using the 'studio' section and then calling this.studio() inside my data function this seems to break. If I change the code below:
ShowStudioController = RouteController.extend({
template: 'showStudio',
waitOn: function () {
return Meteor.subscribe('studio', this.params._id);
},
studio: function () {
return Studios.findOne(this.params._id);
},
data: function () {
return {
studio: this.studio()
};
}
});
to this
ShowStudioController = RouteController.extend({
template: 'showStudio',
waitOn: function () {
return Meteor.subscribe('studio', this.params._id);
},
data: function () {
return Studios.findOne(this.params._id);
}
});
My view renders correctly again. Im unsure where i saw this pattern however I had assumed the function assigned to 'studio' was essentially the same as doing
Template.showStudio.helpers({
studio: function () {
return Studios.findOne(this.params._id)
}
});
but it seems not!

Ember Data - TypeError: Object has no method 'eachRelationship'

So, I'm trying to build routes in my Ember application dynamically with data from an API endpoint, /categories, with Ember Data. In order to do this, I'm adding a didLoad method to my model, which is called by the controller and set to a property of that controller. I map the route to my router, and all that works fine. The real trouble starts when I try to set up a controller with a content property set by data from the server retrieved by findQuery.
This is the error:
TypeError {} "Object /categories/548/feeds has no method 'eachRelationship'"
This is the code:
window.categoryRoutes = [];
App.Categories = DS.Model.extend({
CATEGORYAFFINITY: DS.attr('boolean'),
CATEGORYID: DS.attr('number'),
CATEGORYNAME: DS.attr('string'),
CATEGORYLINK: function () {
var safeUrl = urlsafe(this.get('CATEGORYNAME'));
categoryRoutes.push(safeUrl);
return safeUrl;
}.property('CATEGORYNAME'),
didLoad: function () {
var categoryLink = this.get('CATEGORYLINK');
var categoryId = this.get('CATEGORYID');
App.Router.map(function () {
this.resource(categoryLink, function () {
// some routes
});
});
App[Ember.String.classify(categoryLink) + 'Route'] = Ember.Route.extend({
setupController: function(controller, model) {
// source of error
this.controllerFor(categoryLink).set(
'content',
this.store.findQuery('/categories/' + categoryId + '/feeds', {
appid: 'abc123def456',
lat: 39.75,
long: -105
})
);
}
});
}
});
Any 'halp' is appreciated!
Also, if I'm doing this completely wrong, and there's a more Ember-like way to do this, I'd like to know.
I figured this out. I got this error because I was passing in a string instead of a real 'type' from the App.Helpers object to an extract method in some custom RESTAdapter code I had overridden.
The solution is to pass in the corresponding model helper in App.Helpers using my custom type name.
Something like this in the overridden RESTAdapter.serializer.extractMany method:
var reference = this.extractRecordRepresentation(loader, App.Helpers[root], objects[i]);

Categories