Make sure you have the required packages installed:
iron:router
fourseven:scss
meteoric:ionic-sass
meteoric:ionicons-sass
meteoric:ionic
meteor-ionic
makes extensive use of Blaze Templates. There are two ways to include a Blaze Template into your page: inclusion syntax and block syntax.
Most Meteor developers are already familiar with the inclusion syntax which takes a template like this:
<template name="myTemplate">
<div class="my-template">
Static content here
</div>
</template>
And lets you include it in another template like this:
<h1>Another Template</h1>
{{> myTemplate}}
Which outputs this:
<h1>Another Template</h1>
<div class="my-template">
Static content here
</div>
The block syntax (also called block helpers) is much more interesting. A block helper allows us to create a "wrapper" template like so:
<template name="myTemplate">
<div class="my-template">
{{> UI.contentBlock}}
</div>
</template>
And inject custom content into it when we include it on the page:
<h1>Another Template</h1>
{{#myTemplate}}
Custom content goes here
{{/myTemplate}}
Which outputs this:
<h1>Another Template</h1>
<div class="my-template">
Custom content goes here
</div>
meteor-ionic
uses these "block helpers" to mimic Angular's "directives" feature which is prevalent in Ionic. There are a few reasons for this:
Some components may require several <div>
's or class names which can be difficult to remember. These can be abstracted away into the wrapper template allowing you to simply type a component name such as {{#ionContent}}
.
Using block helpers we can pass simple options to our template (e.g. align='left'
, title='My Modal'
) and let the template convert those options into CSS classes or HTML content.
For example a fictional myPanel
component could be initialized like this:
{{#myPanel title="Meteoric" type="primary"}}
<p>Meteor + Ionic = Meteoric</p>
{{/myPanel}}
And could then output:
<div class="my-panel is-primary">
<div class="my-panel-header">
<h1>Meteoric</h1>
</div>
<div class="my-panel-body">
<p>Meteor + Ionic = Meteoric</p>
</div>
</div>
Some of the more advanced components like ionNavView
, ionNavBar
, ionModal
, etc provide full HTML structures, events and animations all with a single template include.
All meteor-ionic apps must have an ionBody
component at the root. This element has various classes and event handlers attached to it. In your iron:router
layout, make sure you have an ionBody
component surrounding your {{>yield}}
:
{{#ionBody}}
{{>yield}}
{{/ionBody}}
You will almost always want to wrap your templates in an ionContent
component. The ionContent
has two primary responsibilities:
- Implements native-feeling scrolling on the device using
-webkit-overflow-scrolling: touch;
- Positions itself appropriately from the top or bottom of the screen when headers, footers and tabs are present.
Most of your templates will follow this pattern:
{{#ionContent}}
<p>Your content here</p>
{{/ionContent}}
Which will output:
<div class="scroll-content ionic-scroll">
<div class="content overflow-scroll">
<p>Your content here</p>
</div>
</div>
The ionContent
component also accepts arbitrary CSS classes. For example, to use Ionic's built in padding
class to add padding around your content, you can do:
{{#ionContent class="padding"}}
<p>Your content here</p>
{{/ionContent}}
Which would output:
<div class="scroll-content ionic-scroll">
<div class="content overflow-scroll padding">
<p>Your content here</p>
</div>
</div>
To mimic the sliding-back-and-forth navigation UI of mobile apps, meteor-ionic makes use of the three primary technologies:
iron:router
iron:layout
- Meteor's
_uihooks
As previously mentioned, your layout should have an ionBody
component at the root. Inside of this you will want to wrap your yield
in an ionNavView
, which will take care of animating the templates that iron:router
renders. Lastly, you'll probably want an ionNavBar
element at the top of your screen to show the title of the page, as well as navigation items and other action buttons.
{{#ionBody}}
{{> ionNavBar}}
{{#ionNavView}}
{{> yield}}
{{/ionNavView}}
{{/ionBody}}
In the individual templates that get rendered in the navigation stack, you will want to follow this pattern:
{{#contentFor "headerButtonLeft"}}
{{>ionNavBackButton}}
{{/contentFor}}
{{#contentFor "headerTitle"}}
<h1 class="title">Notifications</h1>
{{/contentFor}}
{{#ionView}}
{{#ionContent}}
Content goes here
{{/ionContent}}
{{/ionView}}
The ionView
component simply adds some CSS rules that allow it to be animated properly and the ionContent
component should look familiar by now. However the contentFor
blocks probably need some explaining:
This is where iron:layout
comes into play. Our ionNavBar
component exposes three "regions" that you can insert content into: "headerButtonLeft", "headerButtonRight" and "headerTitle". Whatever content you put inside the contentFor
block will get inserted (and in this case, animated) into the correct region.
To create Ionic style tabs you need to wrap your tabs into an ionTabs
component. You can add the ionic tab classes to determine the style of your tabs. Single tabs are created with the ionTab
element. The text of a tab is set with the title
attribute. If you use icon tabs you can add ionicons with the iconOff
and iconOn
attributes. You can also set a path to link the tab to an iron router route. Example:
{{#ionTabs class="tabs-positive tabs-icon-top"}}
{{> ionTab title="News" path="news" iconOff="ios-paper" iconOn="ios-paper"}}
{{> ionTab title="Todos" path="todos" iconOff="checkmark-circled" iconOn="checkmark-circled"}}
{{> ionTab title="Profile" path="profile" iconOff="person" iconOn="person"}}
{{/ionTabs}}
To make an Ionic style list wrap your content in a ionList
block template.
{{#ionContent}}
{{#ionList class="my-class"}}
{{#each item}}
<h2>{{title}}</h2>
<p>{{subTitle}}</p>
{{/each}}
{{/ionList}}
{{/ionContent}}
To get a nice Ionic styled list item wrap your content in a ionItem
block template. ionItem
can be a list, form, links, etc. It is a very flexible component. I would suggest taking some time to discover all it can do. Below are some examples.
{{#ionList class="my-class"}}
{{#each times}}
{{#ionItem buttonRight=true avatar=true}}
<img src="https://randomuser.me/api/portraits/thumb/men/27.jpg">
<h2>John Smith</h2>
<p>(555) 555-1212</p>
<button class="button button-positive">
{{> ionIcon icon="ios-telephone"}}
</button>
{{/ionItem}}
{{/each}}
{{/ionList}}
Meteor uses Iron:Router. Most are familiar with Iron:Router's pathFor and urlFor helpers. Meteoric lets you tap into those helpers from within ionItem
or ignore them, the choice is yours.
To call IR's pathFor
you would specify your route in the path
attribute.
{{#ionItem path="item.detail" _id:"" data="" query="" hash="" class=""}}...{{/ionItem}}
To call IR's urlFor
you would specify your route in the url
attribute.
{{#ionItem url="item.detail" _id:"" data="" query="" hash="" class=""}}...{{/ionItem}}
And if you want to specify a path without calling any IR helpers specify your route in the path
or route
attribute and make sure not to include any of these attributes data
query
hash
.
{{#ionItem route="item.detail" _id:"" class=""}}...{{/ionItem}}
Lastly you can also pass a raw url by including the href
attribute.
{{#ionItem href="https://google.com" class=""}}...{{/ionItem}}
Raw url
{{! href="https://google.com" }}
{{#ionList}}
{{#each item}}
{{#ionItem href="https://google.com" iconRight=true}}
<h2>{{title}}</h2>
<p>{{subTitle}}</p>
{{> ionIcon icon="ios-arrow-right" }}
{{/ionItem}}
{{/each}}
{{/ionList}}
Passed route from parent (no IR helper)
{{! href="/products/zcZmWRjJztydnCJer" }}
{{#ionList}}
{{#each products}}
{{#with product}}
{{#ionItem product=this route="products.show" iconLeft=true iconRight=true}}
{{> _voteButton}}
<h2>{{name}}</h2>
<p>{{tagline}}</p>
<span class="comments-count">
{{numberOfComments}}
{{> ionIcon icon="ios-chatbubble" }}
</span>
{{/ionItem}}
{{/with}}
{{/each}}
{{/ionList}}
IronRouter's pathFor href
{{! href="/item/details/jkh34k234h?parentId=hkjh45j43k3#reviews" }}
{{#ionList}}
{{#each item}}
{{#ionItem path='item.detail' _id:this._id query=itemQuery hash="reviews" iconRight=true}}
<h2>{{title}}</h2>
<p>{{subTitle}}</p>
{{> ionIcon icon="ios-arrow-right" }}
{{/ionItem}}
{{/each}}
{{/ionList}}
IronRouter's urlFor href
{{! href="http://www.example.com/item/details?parentId=hkjh45j43k3" }}
{{#ionList}}
{{#each item}}
{{#ionItem url='item.detail' query=itemQuery iconRight=true}}
<h2>{{title}}</h2>
<p>{{subTitle}}</p>
{{> ionIcon icon="ios-arrow-right" }}
{{/ionItem}}
{{/each}}
{{/ionList}}
The ionModal
component is quite easy to implement. First, create a template for your modal:
<template name="myModal">
{{#ionModal title="My Modal"}}
<p>My modal content goes here</p>
{{/ionModal}}
</template>
Then attach it to a button
or a
element by passing in the name of the template to the data-ion-modal
attribute.
<button data-ion-modal="myModal">Open Modal</button>