Generating a URL for Twitter users with Iron Router - javascript

I have users that sign in to a Meteor app with Twitter. I'd like to create a profile page route for them with Iron Router that references their Twitter screenName.
I can't work out what should replace the :slug part of the Iron Router code below (there is no property slug in my user document).
this.route('expertPage', {
path: '/profile/:slug',
data: function() { return Meteor.users.findOne({"services.twitter.screenName": this.params.slug}); }
});

First you must provide the slug as a key value pair, an object in a template helper:
userScreenName = function() {
return Meteor.user().services.twitter.screenName;
}
Template.profileLink.helpers({
slugObject: function () {
return {'slug': userScreenName()};
},
screenName: function () {
return userScreenName();
}
});
You can now supply this to the pathFor helper by using
a) with a with block
<template name="profileLink">
{{screenName}}
</template>
b) with direct use as argument
<template name="profileLink">
{{screenName}}
</template>

Related

How to fix FlowRouter.getParam from being 'undefined'

I am adding a new page to a website, and I am copying the code that already exists and is currently working in the website. Why is the FlowRouter.getParam coming up undefined when it works everywhere else?
client/JobInvoice.js
import { Invoices } from '../../../imports/api/Invoice/Invoice';
Template.InvoicePage.onCreated(function(){
const user = FlowRouter.getParam('_id');
console.log(user);
this.subscribe('invoices', user);
});
lib/router.js
Accounts.onLogout(function(){
FlowRouter.go('home');
});
FlowRouter.notFound = {
action: function() {
FlowRouter.go('/404');
}
};
const loggedIn = FlowRouter.group({
prefix: '/secure'
});
loggedIn.route( '/invoice', {
name: 'invoice',
action() {
BlazeLayout.render('FullWithHeader', {main:
'InvoicePage'});
}
});
What am I missing?
FlowRouter allows you to define routes with dynamic attributes (path-to-regexp), which are often representing document ids or other dynamic attributes.
For example
FlowRouter.route('/invoice/:docId', { ... })
would define a route that matches a pattern like /invoice/9a23bf3uiui3big and you usually use it to render templates for single documents.
Now if you want to access the document id as param docId inside the corresponding Template you would use FlowRouter.getParam('docId') and it would return for the above route 9a23bf3uiui3big.
Since your route definitions lacks a dynamic property, there is no param to be received by FlowRouter.getParam.
A possible fix would be
loggedIn.route( '/invoice/:_id', {
name: 'invoice',
action() {
BlazeLayout.render('FullWithHeader', {main:
'InvoicePage'});
}
});
to access it the same way you do for the other templates.
Readings
https://github.com/kadirahq/flow-router#flowroutergetparamparamname
Here is what I ended up doing and it works.
loggedIn.route( '/invoice/:id', {
name: 'invoice',
action() {
BlazeLayout.render('FullWithHeader', {main: 'InvoicePage'});
}
});

Vue.js - using v-on:click and v-link together

I'm developing a Vue.js app and I'm trying to make a log in system using multiple components.
on my App.vue component (which is the "primary" component and has the nav-bar) there is this button:
<a class="nav-item" v-link="'login'" v-if="!user.authenticated">Login</a>
...
import auth from '../auth'
export default {
data(){
return{
user = auth.user
}
}
}
In one other file (/auth/index.js) I define the "auth" methods as such:
...
user: {
authenticated: false
},
login(email, password) {
axios.post(LOGIN_URL, {
email,
password
}).then((response) => {
this.user.authenticated = true;
this.user = response.data;
router.go('/home');
})
.catch((error)=>{
console.log(error);
});
}
And then I have another component name Login.vue that handles the view for the login template and calls the "auth.login" method with the required params.
The thing is that I want to update the user from App.vue with the value from auth.user AFTER he logs in. How should I do that? Do I have to manage the v-on:click and v-link priorities and come up with a new method?
EDIT:
I'm also trying to use the beforeRouteEnter method by I am not being successful
I managed to find a solution adding this:
watch: {
$route () {
this.user = auth.user
}
},
Following the documentation here

How to get the 'keyword' in domain.com/keyword with Iron Router

I am working on a site where I have to search in the DB for string that come after the / on the root domain. I can't find anything about it in the documentation.
I am trying to make it work with Iron Router but any other suggestion would work out.
Thanks for the help!
Edit: Basically I just want to pass anything that comes after domain.com/ to a variable.
Here's something i've been doing so maybe it'll lead you down the right path
Route sends URL params to ownedGroupList template
Router.route('/users/:_id/groups', {
name: 'owned.group.list',
template: 'ownedGroupList',
data: function() {
return {params: this.params};
}
});
Template ownedGroupList can access params object using this.data in onCreated, onRendered, and onDestroyed template event handlers
Template.ownedGroupList.onCreated(function(){
this.subscribe("owned-groups", this.data.params._id );
});
Template ownedGroupList can access params through this variable in helper methods
Template.ownedGroupList.helpers({
groups: function() {
return Groups.find({owner: this.params._id });
}
});
Template ownedGroupList can access params through template.data variable in event handlers
Template.ownedGroupList.events({
'click .a-button': function(event, template) {
var group = Groups.findOne({owner: template.data.params._id });
// do something with group
}
});
Here's a simple route that should do the trick
Router.route('/:keyword', {
name: 'keyword',
template: 'keywordTemplate',
data: function() {
return this.params.keyword;
}
});
This will pass the keyword as the data context to your template and then you can do whatever you want with it. Alternatively you can perform the search straight in the router (especially if you're passing the keyword to a subscription so that the search runs on the server). For example:
Router.route('/:keyword', {
name: 'keyword',
template: 'keywordTemplate',
waitOn: function(){
return Meteor.subscribe('keywordSearch',keyword);
},
data: function() {
return MyCollection.find();
}
});
This second pattern will send your keyword to a subscription named keywordSearch that will execute on the server. When that subscription is ready, the route's data function will run and the data context passed to your keywordTemplate will be whatever documents and fields have been made available in MyCollection.

Session variable not updating when going to a specific route

I'm doing something wrong while setting Session variables and handling the Router
main.js:
Template.global.onCreated(function(){
Session.setDefault("musicFilteredCategory", "latest")
});
router.js:
Router.route("/music/:category?", {
name: "music",
template: "music",
beforeAction: function () {
var category = this.params.category;
Session.set("musicFilteredCategory", category);
}
});
but when I open page "/music/latin-radio" and I check Session.get("musicFilteredCategory") I get "latest" instead of "latin-radio"
later I changed Session.setDefault("musicFilteredCategory", "latest") to outside the Template.global.onCreated({}) and the result is still the same.
What should be the best practice to do this?
I also want to add this feature once this is fixed:
when the user goes to "/music" to be redirected to "/music/:defaultMusicCategory"
PS: I'm using Meteor 1.2.0.1 & Iron Router 1.0.9
As #Kyll pointed out I should use onBeforeAction for the function to run.
This solved part of my problem, but the categories were not being changed when accessing the different routes.
Here's what I had to do:
Router.route("/music/:category?", {
name: "music",
template: "music",
onBeforeAction: function () {
var category = this.params.category;
if (category !== "undefined") {
Session.set("musicFilteredCategory", category);
}
this.render("music");
}
});
This doesn't cover the route "/music" (without the slash) so I also had to add this route, I placed it before the code above
Router.route("/music", {
name: "music",
template: "music"
});
To resolve this I had to move the Session.setDefault() outside the templates scope as they were overriding the Session established on the router, so I had to put them inside a Meteor.startup function
Meteor.startup(function () {
Session.setDefault("musicFilteredCategory", "latest");
});

Vue.js - Global Data from AJAX Call

I'm giving Vue.js a try and so far I'm loving it because it's much simpler than angular. I'm currently using vue-router and vue-resource in my single page app, which connects to an API on the back end. I think I've got things mostly working with a the primary app.js, which loads vue-router and vue-resource, and several separate components for each route.
Here's my question: How do I use props to pass global data to the child components when the data is fetched using an asynchronous AJAX call? For example, the list of users can be used in just about any child component, so I would like the primary app.js to fetch the list of users and then allow each child component to have access to that list of users. The reason I would like to have the app.js fetch the list of users is so I only have to make one AJAX call for the entire app. Is there something else I should be considering?
When I use the props in the child components right now, I only get the empty array that the users variable was initialized as, not the data that gets fetched after the AJAX call. Here is some sample code:
Simplified App.js
var Vue = require('vue');
var VueRouter = require('vue-router')
Vue.use(VueRouter);
var router = new VueRouter({
// Options
});
router.map({
'*': {
component: {
template: '<p>Not found!</p>'
}
},
'/' : require('./components/dashboard.js'),
});
Vue.use(require('vue-resource'));
var App = Vue.extend({
ready: function() {
this.fetchUsers();
},
data: function() {
return {
users: [],
};
},
methods: {
fetchUsers: function() {
this.$http.get('/api/v1/users/list', function(data, status, response) {
this.users = data;
}).error(function (data, status, request) {
// handle error
});
}
}
});
router.start(App, '#app')
Simplified app.html
<div id="app" v-cloak>
<router-view users = "{{ users }}">
</router-view>
</div>
Simplified dashboard.js
module.exports = {
component: {
ready: function() {
console.log(this.users);
},
props: ['users'],
},
};
When dashboard.js gets run, it prints an empty array to the console because that's what app.js initializes the users variable as. How can I allow dashboard.js to have access to the users variable from app.js? Thanks in advance for your help!
p.s. I don't want to use the inherit: true option because I don't want ALL the app.js variables to be made available in the child components.
I believe this is actually working and you are being misled by the asynchronous behavior of $http. Because your $http call does not complete immediately, your console.log is executing before the $http call is complete.
Try putting a watch on the component against users and put a console.log in that handler.
Like this:
module.exports = {
component: {
ready: function() {
console.log(this.users);
},
props: ['users'],
watch: {
users: {
handler: function (newValue, oldValue) {
console.log("users is now", this.users);
},
deep: true
}
}
}
};
In the new version of Vue 1.0.0+ you can simply do the following, users inside your component is automatically updated:
<div id="app" v-cloak>
<router-view :users="users"></router-view>
</div>

Categories

Resources