meteor: How to use Font Awesome with Handlebars? - meteor

First off, I placed this in the HEAD section of my template:
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
I decided I wanted to use the music symbol and inserted it like so:
<div id="close_player"></div>` where the symbol is given by ` fa-music ()
However, when my page loads for some reason I see only fi instead of the Font Awesome symbol I'm supposed to be seeing. The source displays the following:
<div id="close_player"></div>
What is going on, and how do I resolve this?

As Cuberto suggested add the package using mrt,
Then you can do something like this, consider you have iron router and you got 2 icons in every page at your app, and they change according to the route:
<template name='myHomeTemplate'>
<i class={{iconOne}}></i>
<i class={{iconTwo}}></i>
</template>
Then in your router logic you can do
this.route('home', {
path: '/',
template: 'myHomeTemplate',
layoutTemplate: 'layout',
yieldTemplates: {
'myAsideTemplate': {to: 'aside'},
'myFooter': {to: 'footer'}
},
data: {
iconOne: 'fa fa-music',
iconTwo:'fa fa-camera'
}
});

First of all, don't put CSS links in your head. Just add the meteorite package - mrt add font-awesome. This will automatically add the CSS link when you run the app, and it will concatenate and minify it with all your other CSS in deployment. Then, just use the icons the font awesome way:
<i class="fa fa-music"></i>

Related

VueJS component won't render on front end (possibly Drupal issue)

The site I'm currently working on is built in Drupal 7. I have one form that requires user input so I'm attempting to build it with VueJS. The form is contained all within one template file (.tpl.php) and all the content is provided in this template file or via the VueJS Javascript (nothing is coming from the CMS).
The issue I have is that the Vue components are not rendering on the front-end, but when I copy the code into a JSFiddle they do, so I'm guessing it is an issue with the interaction between VueJS and Drupal. Here is a screenshot of my markup when inspecting...
Here is the code from the .tpl.php file...
<div id="app">
<form>
<div>
<label for="year">Per Year</label>
<input type="radio" name="frequency" id="year" value="year" v-model="frequency" checked>
<label for="month">Per Month</label>
<input type="radio" name="frequency" id="month" value="month" v-model="frequency">
</div>
</form>
<ul class="plans">
<template id="plan-component">
<h2 class="plan-name">{{ name }}</h2>
<h2 class="plan-cost">{{ price }}</h2>
<h2 class="plan-tagline">{{ tagline }}</h2>
Choose this plan
</template>
<li>
<plan-component :frequency="frequency"
name="Basic"
tagline="Basic tagline"
price-yearly="Free"
price-monthly="Free"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Rec"
tagline="Rec tagline"
price-yearly="3"
price-monthly="4"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Team"
tagline="Team tagline"
price-yearly="4"
price-monthly="5"
></plan-component>
</li>
<li>
<plan-component :frequency="frequency"
name="Club"
tagline="Club tagline"
price-yearly="5"
price-monthly="6"
></plan-component>
</li>
</ul>
</div>
..and the code from my JS file...
Vue.component('plan-component', {
template: '#plan-component',
props: ['frequency', 'name', 'tagline', 'priceYearly', 'priceMonthly'],
computed: {
'price': function() {
if (this.frequency === 'year') {
return this.priceYearly;
} else {
return this.priceMonthly;
}
}
},
methods: {
makeActivePlan() {
// We dispatch an event setting this to become the active plan
this.$dispatch('set-active-plan', this);
}
}
});
new Vue({
el: '#app',
data: {
frequency: 'year',
activePlan: {name: 'no', price: 'You must select a plan!' }
},
events: {
'set-active-plan': function(plan) {
this.activePlan = plan;
}
},
});
And here is the JSFiddle which outputs the components correctly - https://jsfiddle.net/2xgrpLm6/
What browser are you using? <template> tags are not supported in IE.
Another idea is to make sure you are never using fragment components (meaning wrap everything inside your template with a div like so:
<template id="foobar">
<div>
CONTENT HERE
</div>
</template>
Lastly, have you turned on Vue debug mode? Before you instantiate your Vue instance, set Vue.config.debug = true and see if you get console errors then.
Try moving the <template id="plan-component">...</template> code outside of the Vue instance. I.e., such that it is not contained within <div id="app">...</div>.
This has solved a similar problem for me in the past, though I'm not sure if it applies here.
For anyone having a similar issue, the solution was simple. After Jeff suggested turning on Vue debug mode (and downloading the Dev version of Vue JS instead of minified - https://vuejs.org/guide/installation.html) the console gave the error [Vue warn]: Cannot find element: #app.
The issue was that Drupal was loading my scripts in the <head>, before <div id="app"> was loaded in the DOM. As such #app couldn't be found. After outputting the scripts before the closing <body> tag all was sorted. See here for more information [Vue warn]: Cannot find element

passing arguments to iron:router pathFor

I'm building a menu in Meteor and missing something in the syntax.
I can only guess it's simple but couldn't find any strait question or answer about this, help appreciated.
So, I have one template to rule dem all:
<template name="navigator">
<div class="navigator">
{{>navButton type="home"}}
{{>navButton type="find"}}
{{>navButton type="account"}}
</div>
</template>
my navButton template looks like this:
<template name="navButton">
<div class="navButton">
<p>
{{#if type}}
<a href="{{pathFor type}}"</a>
{{/if}}
</p>
</div>
</template>
the {{pathFor type}} doesn't work.
How can I simply use the type argument string WITHOUT ANY JAVASCRIPT (of course I'm naming the route and templates using the same name)
update:
i don't want to do this due to an implementation of a security pattern:
{{type}}
If you have the routes already set as my example, you can use
Home
Example of route mapping:
Router.route('/', {
name: 'home'
});

How to route html pages on clicks in meteor?

I am a newbie in Meteor. I am developing an app having a login page that must redirect to certain pages as per the login id.There are certain click events which opens up html pages.I have the hard code data in the pages to check the flow now.I have the html pages as well designed, but I am not able to link them for click events and login. Please help.
Here is one way to do it:
In your HTML file, something like this:
<head>
<title>Duckbilled Platypus</title>
</head>
<template name='layout'>
{{> banner}}
{{> yield}}
</template>
<template name="banner">
<h1 class="chocolatefont">Platypi of the World Unite! (Duckbilled, that is)</h1>
<hr/>
</template>
<template name="main">
<div id="templateMain" name="templateMain">
<h2>RAVES</h2>
<p>No Raves yet</p>
<h2>RANTS</h2>
<p>No Rants yet</p>
<h2>RANDOM</h2>
The Legend of NFN Oscar
<br/><br/>
NFN Oscar's donut
<br/><br/>
Alliteration Station ("Ben's Bizarre Bazaar")
<br/><br/>
Boomeranging Telescopic and Kaleidoscopic Phrase Mazes
<br/><br/>
Acrostics
<br/><br/>
Homonym Homie
</div>
</template>
...and then add whichever templates you want for the pages you want to route to; in my case, it's one for each "href" referenced in the anchor tags (nfnoscar, nfnoscarsdout. etc.)
The "yield" (which means, "insert here whatever the router says corresponds to the URL") requires Iron:Router, which you say you already have.
In your JS file, something like this:
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {
name: 'main',
template: 'main'
});
Router.route('/nfnoscar', {
name: 'nfnoscar',
template: 'nfnoscar'
});
Router.route('/nfnoscarsdonut', {
name: 'nfnoscarsdonut',
template: 'nfnoscarsdonut'
});
Router.route('/alliterationstation', {
name: 'alliterationstation',
template: 'alliterationstation'
});
Router.route('/btakpm', {
name: 'btakpm',
template: 'btakpm'
});
Router.route('/homonyms', {
name: 'homonyms',
template: 'homonyms'
});
Router.route('/acrostics', {
name: 'acrostics',
template: 'acrostics'
});
Now, whichever link is clicked, the corresponding page is loaded by means of the "yield" and the Iron Router routing.
You can see this particular app and how it works when you click the links, etc., at my "sandbox" Meteorsite here.

Path works on desktop, but not mobile

I've a tab bar on a responsive app I'm building:
<template name="tabNav">
<nav class="bar bar-tab">
<a class="tab-item" id="groups-nav" href="{{pathFor 'groupsList'}}">
<span class="icon icon-star-filled"></span>
<span class="tab-label">Groups</span>
</a>
<a class="tab-item active" id="games-nav" href="{{pathFor 'locationSet'}}">
<span class="icon icon-list"></span>
<span class="tab-label">Games</span>
</a>
<!-- more code -->
</template>
The pathFor 'groupsList' works on desktop, but not on mobile. You can try it out here: pp-groups.meteor.com.
This is a prototype only and doesn't use any real data. All of my views code is available here: https://github.com/stewartmccoy/pp-groups/tree/master/groups/client/views
These are my defined routes:
Router.map(function() {
this.route('layout', {
path: '/',
template: 'getLocation',
layoutTemplate: 'getLocation',
yieldTemplates: {
'tabNav': {to: 'footer'}
}
});
this.route('locationSet', {
path: '/locationSet',
template: 'locationSet',
layoutTemplate: 'locationSet'
});
this.route('groupsList', {
path: '/groupsList',
template: 'groupsList',
layoutTemplate: 'groupsList'
});
});
Why doesn't the pathFor work on mobile? (It at least doesn't work in Xcode iOS simulator or on iPhone Mobile Safari or Chrome).
The push.js component is causing the issue. You can still use Rachet with Iron Router by disabling push.js. Per rachet's documention you can disable push by adding a data-ignore tag to your HTML link.
<!-- Use data-ignore="push" to prevent the push.js interception -->
<a href="http://www.google.com" data-ignore="push">Google<a>
Routing issue:
Removing the ratchet package fixed it for me. Looks like ratchet uses it's own way of linking between templates which is incompatible with iron-router. Removing ratchet removes the UI elements, but the routing works on mobile: http://pp-groups-fixed.meteor.com. You could use a strictly UI library, like bootstrap to make the UI elements, or maybe even just the ratchet's UI components. If you want to fully use ratchet, you will most likely have to forgo IronRouter.
Other things to fix:
Layout Templates
When using meteor and iron-router, a layout template is a template with common elements, with a {{> yield}} placed where you want the regular templates to show up.
You actually only have one real layout template in your code, in groups.html there is a layout template named layout, and it is unused.
In your code, regular templates are being misused as layout templates, because they don't have {{> yield}} in them. Also, the tabNav template is being placed using iron-router, yet you have already included it in each template with {{> tabNav}}.
So, you can simply get rid of the layout template code in your iron router, and your app will still function:
Router.map(function() {
this.route('layout', {
path: '/',
template: 'getLocation',
// layoutTemplate: 'getLocation',
// yieldTemplates: {
// 'tabNav': {to: 'footer'}
// }
});
this.route('locationSet', {
path: '/locationSet',
template: 'locationSet',
// layoutTemplate: 'locationSet'
});
this.route('groupsList', {
path: '/groupsList',
template: 'groupsList',
// layoutTemplate: 'groupsList'
});
});
A better way is to take out all the common code, the header, general structure of the page, tab bar, and put it in a layout template. Add a {{> yield}} where you want the page template to render. Refer to this layout template in your router as layoutTemplate.
Another sidenote, iron-router automatically looks for the template with the same name as the route, if no template is defined. So if you are writing this.route('groupsList', ... you don't need to write template: 'groupsList' as well.
Data
Your past-game.js file should be named get-location.js. Yes, the name itself doesn't matter, but that is getLocation's complimentary code, not postGame's. Same with scheduled-games.js and locationSet. Look at the Template.templateName.helpers to see how the code corresponds.
Of course, ideally this data should be in a collection. For now, instead of creating the data as arrays with var, you could create a seperate file with your data as global variables. Simply define as PastGames = [...], then use the template helpers to return the data you need.

Rerun Helper Functions on Route Change for Active Links

I've been playing around with Meteor + Iron Router for a multi-page app I'm working on and I'm getting stuck on helper functions for named yields. Specifically, I've been trying to get the active class for my navbar tabs to update on each route change.
Below is the relevant code for my project:
router.js
Router.configure({
layoutTemplate: 'mothership',
yieldTemplates: {
'header' : {to: 'header'},
'footer': {to: 'footer'}
},
});
Router.map(function () {
// Home page
this.route('home', {
path: '/',
template: 'home',
});
this.route('about', {
path: '/about',
template: 'about',
});
this.route('emails', {
path: '/emails',
template: 'emails',
});
this.route('people', {
path: '/people',
template: 'people',
});
});
mothership.html
<template name="mothership">
Skip to content
<div id="wrap">
<!-- header -->
<div>{{yield 'header'}}</div>
<div id="content">{{yield}}</div>
</div>
<div id="push"></div>
<div id="footer">
{{yield 'footer'}}
</div>
</template>
header.html
...bootstrap stuff...
<a class="navbar-brand" href="{{pathFor 'home'}}">Mailchacho</a>
<li class="{{activeRoute 'about'}}">About</li>
<li class="{{activeRoute 'emails'}}">Sent Emails</li>
<li class="{{activeRoute 'people'}}">People</li>
...bootstrap stuff...
header.js
Handlebars.registerHelper('activeRoute', function(name) {
var active = location.pathname === Router.path(name);
return (active) ? 'active' : '';
});
// I know I can use Template.headers.helpers... to do this as well, I just found the registerHelper to be cleaner.
When I load a page from scratch, the proper active class is assigned, but when a route is changed on-page, the active class doesn't update. Using breakpoints, I can see the 'activeRoute' function isn't called on a change.
What's interesting is if I add a data dictionary to router.js, it does update. My guess is having the data dictionary indicates that something has changed between routes, forcing a refresh. What I'd like to do is have this refresh occur without needing to pass a data dictionary.
Since Iron Router is still fairly new, I haven't been able to able to find much online. The closest I've found is this issue on github (https://github.com/EventedMind/iron-router/issues/103), but the last comment was never resolved, which seems to be similar to mine.
With the above in mind, is there any way I can signal for a helper function to be rerun on a route change without passing a dummy data dictionary? I was thinking that something like Deps.autorun might be needed, but that doesn't feel right. I'm still pretty new to Meteor & Iron Router so any help here would be appreciated. Thanks!
Yours is a common problem so Mike Fitzgerald has built a package just for this purpose:
https://atmosphere.meteor.com/package/iron-router-active
The given example is like:
<nav>
<ul>
<li class="{{ isActive 'dashboard' }}">...</li>
<li class="{{ isActive 'dashboard|root' }}">...</li>
<li class="{{ isActive 'users' 'on' }}">...</li>
<li class="{{ isActivePath 'products' }}">...</li>
</ul>
</nav>
andd works through handlebars helpers which are called isActive, isActivePath, isNotActive and isNotActivePath.
I use meteor add zimme:active-route now. It works with iron:router, kadira:flow-router and meteorhacks:flow-router.
Just two examples: Output active class:
<li class="{{isActiveRoute 'home'}}">...</li>
Custom class:
<li class="{{isActiveRoute 'home' class='is-selected'}}">...</li>
https://atmospherejs.com/zimme/active-route

Resources