Exploring Meteor with multi level push menu


#1

Hi everyone, this is my first time i build an app using meteor / javascript stuff…

So, in this case, i would like to share about my experience when i made this app. actually this is the simple web that just using a multi level push menu for navigation just like http://tympanus.net/Development/MultiLevelPushMenu/.

to see the demo you can click here http://charlist.meteor.com/

ok so lets get started…

  1. get the external files…
    there are 7 items in total : classie.js, mlpushmenu.js, modernizr.custom.js, component.css, demo.css, icons.css, normalize.css
    you can dowload it from this link http://tympanus.net/codrops/2013/08/13/multi-level-push-menu/

  2. create compability folder and characters folder
    create new folder and name it “compability” and move your external js files to that folder.
    the characters folder will hold all your working javascript file and also your html. actually this is my style so its not a necessary to follow me to create the characters folder. you still can code in your main js file and your main html.
    so your structure file will be look like this

  3. creating your main html and js file
    inside the characters folder create 2 new files for your main web. i called it heroes.html and heroes.js. why i name it “heroes” ? because i just finished The Flash tv show and give me the idea to make this thing.

  4. heroes.html
    create a new template for a main template and one new template again for the multilevel push menu.

    {{>MultiLevelPushMenu}}

if you already have download the source code from the link above, you can just copy-paste the code from <div class="container"> until </div><!-- /container --> oh btw, i’m using with the index3.html.

from here you can customize the navigation such removing what you dont need. in my case i remove a lot of things so just become simple like this

 <template name="MultiLevelPushMenu">
    <div class="container">
    <!-- Push Wrapper -->
    <div class="mp-pusher" id="mp-pusher">
        <h2 style="margin-left: 20px"><a href="#" id="trigger" class="menu-trigger">Open/Close Menu</a></h2>
        <!-- mp-menu -->
        <nav id="mp-menu" class="mp-menu">
            <div class="mp-level">
                <h2 class="icon icon-star">All Categories</h2>
                <ul>
                    <li><a class="icon icon-shop" href="/MainTemplate">Home</a></li>
                    <li class="icon icon-arrow-left">
                        <a class="icon icon-data" href="#">Gallery</a>
                        <div class="mp-level">
                            <h2 class="icon icon-data">Gallery</h2>
                            <a class="mp-back" href="#">back</a>
                            <ul>
                                <li class="icon icon-arrow-left">
                                    <a class="icon icon-world" href="#">DC</a>
                                    <div class="mp-level">
                                        <h2 class="icon icon-world">DC</h2>
                                        <a class="mp-back" href="#">back</a>
                                        <ul>
                                            <li>
                                                <a class="icon icon-star" href="#" id="DCHeroId">Hereos</a>
                                            </li>
                                            <li>
                                                <a class="icon icon-diamond" href="#" id="DCVillainId">Villains</a>
                                            </li>
                                        </ul>
                                    </div>
                                </li>
                                <li class="icon icon-arrow-left">
                                    <a class="icon icon-world" href="#">Marvel</a>
                                    <div class="mp-level">
                                        <h2 class="icon icon-world">Marvel</h2>
                                        <a class="mp-back" href="#">back</a>
                                        <ul>
                                            <li>
                                                <a class="icon icon-star" href="#" id="MarvelHeroId">Hereos</a>
                                            </li>
                                            <li>
                                                <a class="icon icon-diamond" href="#" id="MarvelVillainId">Villains</a>
                                            </li>
                                        </ul>
                                    </div>
                                </li>
                            </ul>
                        </div>
                    </li>
                    <li><a class="icon icon-search" href="#" id="ViewGrid">View in Grid</a></li>
                    <li><a class="icon icon-phone" href="#" id="ContactMe">Contact Me</a></li>
                </ul>
            </div>
        </nav>
        <!-- /mp-menu -->
        <!-- this is for emulating position fixed of the nav -->

    </div><!-- /pusher -->
    </div><!-- /container -->
        </template>

5… dividing per level
the key success of this multi level push menu is to make every level of navigation to a new template (except the lowest level) and then combine it to parent template. so if i have a menu like this

then it should become another different template. in my case, i can breakdown 3 level. so if you click the gallery it can breakdown to level which character came from. is it from DC or Marvel universe. and if you chose the DC, you still can breakdown it to level heroes/villains.

so we are going to mutilate the html part into some template according to the level. your code are going to be like this.

<template name="MultiLevelPushMenu">
    <div class="container">
        <!-- Push Wrapper -->
        <div class="mp-pusher" id="mp-pusher">
            <h2 style="margin-left: 20px"><a href="#" id="trigger" class="menu-trigger">Open/Close Menu</a></h2>
            <!-- mp-menu -->
            <nav id="mp-menu" class="mp-menu">
                <div class="mp-level">
                    <h2 class="icon icon-star">All Categories</h2>
                    {{>test}}
                </div>
            </nav>
            <!-- /mp-menu -->
            {{>scroller}}

        </div><!-- /pusher -->
    </div><!-- /container -->
</template>

<template name="test">
    <ul>
        <li><a class="icon icon-shop" href="/MainTemplate">Home</a></li>
        <li class="icon icon-arrow-left">
            <a class="icon icon-data" href="#">Gallery</a>
            <div class="mp-level">
                <h2 class="icon icon-data">Gallery</h2>
                <a class="mp-back" href="#">back</a>
                <ul>
                    <li class="icon icon-arrow-left">
                        <a class="icon icon-world" href="#">DC</a>
                        <div class="mp-level">
                            <h2 class="icon icon-world">DC</h2>
                            <a class="mp-back" href="#">back</a>
                            {{>testdc}}
                        </div>
                    </li>
                    <li class="icon icon-arrow-left">
                        <a class="icon icon-world" href="#">Marvel</a>
                        <div class="mp-level">
                            <h2 class="icon icon-world">Marvel</h2>
                            <a class="mp-back" href="#">back</a>
                            {{>testmarvel}}
                        </div>
                    </li>
                </ul>
            </div>
        </li>
        <li><a class="icon icon-search" href="#" id="ViewGrid">View in Grid</a></li>
        <li><a class="icon icon-phone" href="#" id="ContactMe">Contact Me</a></li>
    </ul>
</template>

<template name="testdc">
    <ul>
        <li>
            <a class="icon icon-star" href="#" id="DCHeroId">Hereos</a>
        </li>
        <li>
            <a class="icon icon-diamond" href="#" id="DCVillainId">Villains</a>
        </li>
    </ul>
</template>

<template name="testmarvel">
    <ul>
        <li>
            <a class="icon icon-star" href="#" id="MarvelHeroId">Hereos</a>
        </li>
        <li>
            <a class="icon icon-diamond" href="#" id="MarvelVillainId">Villains</a>
        </li>
    </ul>
</template>

level 1, i named it “test” template. and level 2 i named it “testdc” and “testmarvel”

6… template scroller
if you notice there is a template scroller replacing the comment <!-- this is for emulating position fixed of the nav -->. yes thats right ! When i choose the Gallery-DC-Heroes link, my scroller side will show a bunch of heroes list from DC universe just like batman, superman. if i choose DC villain it will show
ares, brainiac, etc. in this case i’m using the reactive session and of course a new template again (template logo) to show them. for additional i show it using listview from kendo ui core. so you have to add kendo-ui-core package meteor add telerik:kendo-ui-core-bootstrap-theme

<template name="scroller">
    <div class="scroller"><!-- this is for emulating position fixed of the nav -->
        <div class="scroller-inner">

            {{#if currentViewIs "GridHeroes"}}
                {{>GridHeroes}}
            {{else}}
                {{#if currentViewIs "addHero"}}
                    {{>addHero}}
                {{else}}
                    {{#if currentViewIs "DCHero"}}
                        {{>logo}}
                    {{else}}
                        {{#if currentViewIs "MarvelHero"}}
                            {{>logo}}
                        {{else}}
                            {{#if currentViewIs "MarvelVillain"}}
                                {{>logo}}
                            {{else}}
                                {{#if currentViewIs "DCVillain"}}
                                        {{>logo}}
                                    {{else}}
                                        {{#if currentViewIs "Contact"}}
                                            {{>contactme}}
                                        {{/if}}
                                {{/if}}
                            {{/if}}
                        {{/if}}
                    {{/if}}
                {{/if}}
            {{/if}}

        </div><!-- /scroller-inner -->
    </div><!-- /scroller -->
</template>

<template name="logo">
    <div id="exampleListView">

        <div class="demo-section k-header wide">
            <div id="listView">

            </div>
            <div id="pager" class="k-pager-wrap"> </div>
        </div>
    </div>
</template>

before we get into the js code, make sure your heroes.html file will look like this

for GridHeroes and contactme template, i’m not gonna discuss it because its just a template that using a listview. just make sure, now you have 7 templates : MainTemplate, MultilevelPushMenu, test, testdc, testmarvel, scroller, logo.

7… hereos.js
lets get started from the first template that we created, MainTemplate. this is the grand parent template that hold the multi level push menu feature. so you have to call the function of the multi level push menu when the MainTemplate rendered.

Template.MainTemplate.rendered = function(){
        window.mlPushMenu = new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ) );
       
    };

8… reactive session
as i said before we are going to use the reactive session to show the data. different template not always means that you should make different page of html.

Template.scroller.currentViewIs = function(view) {
        if(Session.get('currentView') == view)
            return true;
        return false;
    };

    Template.test.events ({

        'click .icon-search':function(event,template){
            Session.set('currentView', 'GridHeroes');
        },

        'click .icon-male':function(){
            Session.set('currentView', 'addHero');
        },

        'click .icon-phone':function() {
            Session.set('currentView', 'Contact');
        }
    });

    Template.testdc.events ({
        'click #DCVillainId' :function() {
            Session.set('currentView', 'DCVillain');
        },

        'click #DCHeroId' :function() {
            Session.set('currentView', 'DCHero');
        }
    });

    Template.testmarvel.events ({
        'click #MarvelVillainId' :function() {
            Session.set('currentView', 'MarvelVillain');
        },

        'click #MarvelHeroId' :function() {
            Session.set('currentView', 'MarvelHero');
        }
    });

Template.logo.rendered = function() {

        dataSource = new kendo.data.DataSource({
            sort: {
                field: 'AKA',
                dir: 'asc'
            },
            pageSize: 6
        });

        if(Session.get('currentView') == null)
        {
            dataSource.data(COMIC.find().fetch());
        }
        else if((Session.get('currentView') == 'DCHero') || (Session.get('currentView') == 'DCVillain') )
        {
            var regex2;
            if(Session.get('currentView') == 'DCHero')
            {
                regex2 = new RegExp('Hero'+'.*', 'i');
            }
            else
            {
                regex2 = new RegExp('Villain'+'.*', 'i');
            }

            var regex = new RegExp('DC'+'.*', 'i');
            dataSource.data(COMIC.find({Universe: {$regex: regex}, Status:{$regex: regex2}}).fetch());
        }
        else if((Session.get('currentView') == 'MarvelHero') || (Session.get('currentView') == 'MarvelVillain') )
        {
            var regex2;
            if(Session.get('currentView') == 'MarvelHero')
            {
                regex2 = new RegExp('Hero'+'.*', 'i');
            }
            else
            {
                regex2 = new RegExp('Villain'+'.*', 'i');
            }

            var regex = new RegExp('Marvel'+'.*', 'i');
            dataSource.data(COMIC.find({Universe: {$regex: regex}, Status:{$regex: regex2}}).fetch());
        }
        else
        {
            //alert('session unknown');
        }

        $("#pager").kendoPager({
            dataSource: dataSource
        });

        $("#listView").kendoListView({
            dataSource: dataSource,
            selectable: "multiple",
            dataBound: onDataBound,
            change: onChange,
            template: '<div class="product">' +
            '<img src="#:ProfilePict#"  width="100px" height="100px" />' +
            '<h3>#:AKA#</h3>' +
            '</div>'
        });


        function onDataBound() {
            kendoConsole.log("ListView data bound");
        }

        function onChange() {

            var data = dataSource.view(),
                selected = $.map(this.select(), function(item) {
                    return data[$(item).index()].AKA;
                });

            Session.set('AKASession', selected);

            //var ds = dataSource.data(COMIC.find({ProfilePict: selected}).fetch());
            Modal.show('exampleModal');

        }
    };

ok thats all… sorry for my bad english, hope you can understand it.
if you have any question or suggestion you can reply it to me below…


Multilevel push-menu in meteor