Desmond  Gerber

Desmond Gerber

1653737280

KambojaJS: New Meteoris, A MVC and Modular Framework for Meteor

WHAT IS METEORIS?

Meteoris is a Realtime MVC + Modular Javascript Framework based on Meteor 1.2.0. This is the latest version of Meteoris out there. In this version, Meteoris still doesn't have a code generator. If you prefer using the old version of meteoris, please use this version https://github.com/radiegtya/meteoris-v1.

QUICKSTART

1. Install Meteor, Create New Project & Download Required Packages

#install meteor
curl https://install.meteor.com/ | sh

#create new meteor project
meteor create my-meteoris-app

#the main module
meteor add meteoris:core

#another important module
meteor add meteoris:theme-admin
meteor add meteoris:user
meteor add meteoris:role

#remove meteor unused package
meteor remove insecure
meteor remove autopublish

2. Create hooked Navbar and Sidebar inside your "root/client/hook" folder

We can easily hook navbar and sidebar to customize our own sidebar and navbar although we are using meteoris:admin-theme template. The content of each template is using navbar and sidebar Admin LTE style. Make sure you are using correct theme name "meteoris_themeAdmin_hookNavbar" for sidebar, and "meteoris_themeAdmin_hookSidebar" for navbar.

<template name="meteoris_themeAdmin_hookNavbar">
    <div class="navbar-custom-menu">
        <ul class="nav navbar-nav">
            {{#if currentUser}}
            <!-- User Account: style can be found in dropdown.less -->
            <li class="dropdown user user-menu">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                    <img src="/images/user.png" class="user-image" alt="User Image">
                    <span class="hidden-xs">{{currentUser.profile.name}}</span>
                </a>
                <ul class="dropdown-menu">
                    <!-- User image -->
                    <li class="user-header">
                        <img src="/images/user.png" class="img-circle" alt="User Image">
                        <p>
                            {{currentUser.profile.name}}
                        </p>
                    </li>
                    <!-- Menu Footer-->
                    <li class="user-footer">
                        <div class="pull-left">
                            <a href="#" class="btn btn-default btn-flat">Profile</a>
                        </div>
                        <div class="pull-right">
                            <a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
                        </div>
                    </li>
                </ul>
            </li>
            {{else}}
            <li>
                <a href="/meteoris/user/login">Login</a>
            </li>
            {{/if}}
        </ul>
    </div>
</template>

"at root/client/hook/navbar.html"

var ctrl = new Meteoris.UserController();

Template.meteoris_themeAdmin_hookNavbar.events = {
    'click #btnLogout': function(){
        ctrl.logout();
    }
};

"at root/client/hook/navbar.js"

<template name="meteoris_themeAdmin_hookSidebar">
    <!-- Left side column. contains the logo and sidebar -->
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            {{#if currentUser}}
            <!-- Sidebar user panel -->
            <div class="user-panel">
                <div class="pull-left image">
                    <img src="/images/user.png" class="img-circle" alt="User Image">
                </div>
                <div class="pull-left info">
                    <p>{{currentUser.profile.name}}</p>
                    <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                </div>
            </div>
            {{/if}}
            <!--search form--> 
            <form action="#" method="get" class="sidebar-form">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="Search...">
                    <span class="input-group-btn">
                        <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
                    </span>
                </div>
            </form>
            <!--/.search form--> 
            <!-- sidebar menu: : style can be found in sidebar.less -->
            <ul class="sidebar-menu">
                <li class="header">MAIN NAVIGATION</li>
                <li><a href="/"><i class="fa fa-home"></i> Home</a></li>
                <!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
                <!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
                <li class="header">ADMIN AREA</li>                
                <li class="treeview">
                    <a href="#">
                        <i class="fa fa-gears"></i>
                        <i class="fa fa-angle-left pull-right"></i>
                        <span>Setting</span>                                
                    </a>
                    <ul class="treeview-menu">                        
                        <li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>                        
                        <li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>                        
                        <li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>                                         
                        <li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>                                                
                    </ul>
                </li>
                <!--{{/if}}-->
            </ul>
        </section>
        <!-- /.sidebar -->
    </aside>        
</template>

"at root/client/hook/sidebar.html"

3. Creating Home/Site Page

Meteoris use simple MVC or MVVM + Modular paradigm to structuring app. Please use this standard structure to achieve best result when using meteoris.

3.1. Folder Structure

root/
  meteorusernameorgroup:module/
	client/             # Client folder
	   views/           # Views for html/js files
	lib/                # Both Access folder
	   collections/     # Collections folder
	   controllers/     # Controllers Folder
	   router.js        # Router js file
	server/             # Server folder			   

3.2. Router Meteoris using Kadira Flow Router to linking between pages. Because we are using modular technique, assume that we are using my meteor account called "radiegtya" and using module name called "site". So we should make folder under root folder called "radiegtya:site". To use modular router, simply follow this step:

  • create router file on "root/radiegtya:site/lib/router.js", and type this code
/**
create group routes, so every router has prefix radiegtya
*/
var groupRoutes = FlowRouter.group({
    prefix: '/radiegtya',
    name: 'radiegtya',
});

/**
create the main router called site, and use BlazeLayout render "meteoris_themeAdminMain" from metoris:theme-admin package, and accessing template called "radiegtya_siteIndex"
*/
groupRoutes.route('/site', {
    action: function() {
        BlazeLayout.render('meteoris_themeAdminMain', {content: "radiegtya_siteIndex"});
    },   
});
  • We are not yet able to use this router, but once you have created the views, you can access this page by calling this route:
localhost:3000/radiegtya/site

3.3. Creating Controller for Site Controller actually just a method to be called inside your template js, and this will make your code more modular and readable.

  • Create controller file on "root/radiegtya:site/lib/controller/SiteController.js"
/*
create a namespace called Radiegtya.SiteController
*/
Namespace('Radiegtya.SiteController');

/**
Create controller which extends Meteoris Controller
*/
Radiegtya.SiteController = Meteoris.Controller.extend({
	constructor : function() {
            // set default counter at constructor
            Session.setDefault('counter', 0);
        },
        /* passing data to index helpers template */
	index: function() {			        
		//return some value, to be passed on index.js
		return {
		    counter: this.getCounter(),
			myName: "Ega Radiegtya",
			myHobby: "Drinking Coffee"
		};
	},
	getCounter: function(){
		return Session.get("counter");
	},
	setCounter: function(counter){
		Session.set('counter', this.getCounter() + 1);
	}
});

3.4. Creating Views Page for Site

  • create views index file on "root/radiegtya:site/client/views/index.html". Look at the template naming convention, it use "meteorusername_moduleAction" namespacing, so for this views we are gonna use "radiegtya_siteIndex". Which is "radiegtya" for meteor username, "site" for the module name, and "Index" in camel case after site as action name.
<template name="radiegtya_siteIndex">
	<div class="content">
		<div class="box">
			<div class="box-body">
				<button>Click Me</button>
				<p>
				You've pressed the button {{counter}} times.
				</p>
			</div>
		</div>
	</div>
</template>

because we are installing meteoris:theme-admin, you can use adminLTE styling and html inside your views html file. We are using meteor example to make You more familiar with the code.

  • Don't forget to add the js file for the index. Create this file on "root/radiegtya:site/client/views/index.js"
var ctrl = new Radiegtya.SiteController();

/**
In the template helper section we are using index() method to get object return value from controller. It's because index was the action and also the file name suffix. This structure will make You easier to get jobs done, when your team getting bigger and the code getting bigger.
*/
Template.radiegtya_siteIndex.helpers({
	myName: function () {
		return ctrl.index().myName;
	},
	myHobby: function () {
		return ctrl.index().myHobby;
	},	
    counter: function () {
      return ctrl.index().counter;
    }
  });

/**
in the template events, we don't need to use index() method to call any action. Because it just simply method calling through controller.
*/
Template.radiegtya_siteIndex.events({
    'click button': function () {
      //increment the counter when button is clicked
      ctrl.setCounter();      
    }
});

Now finally access this route to check your apps.

localhost:3000/radiegtya/site

enter image description here

Awesome! We are successfully creating our simple app in MVC and Modular way with very easy setup. Ofc with amazing template which is reusable. You can also use this code to create a meteor package easily.

3.5. Creating Collection You can use aldeed:collection2, aldeed:simple-schema, and dburles:collection-helpers in our Meteoris collection. Future explanation will be comming soon. ======== COMING SOON =========

3.6. Creating Server You can use reywood:publish-composite here. Future explanation coming soon. ======== COMING SOON =========

3.7. Using Meteoris Plugin For now You can refer to the below this Quick Start article.

====================================================================================

#1. INSTALLATION

meteor add meteoris:core

it will also installing it's dependencies, which are:

1.1. meteoris:flash

Meteoris Package to show Flash/Toast Error/Success in your bottom right screen.

enter image description here

how to use in your js file:

//set flash message example
Meteoris.Flash.set('success', 'Data Successfully added');
Meteoris.Flash.set('danger', 'Data Failed to be added');

how to use in your html file:

<!-- Simply place this code on your html view anywhere -->
{{> meteoris_flash}}

1.2. meteoris:form-validation

Meteoris package to validate form easily. This Meteoris.FormValidation extension depends on collection2 and simpleschema:

enter image description here

AccountType = new Mongo.Collection("accountType");

var schemas = new SimpleSchema({
    accountClassId: {
        type: String,
        label: "Kelas Akun",
    },    
});

AccountType.attachSchema(schemas);
  • how to use in your js helper:
    /* show error message on view */
    error: function(field) {
        return Meteoris.FormValidation.error(YourCollectionName, field);
    },
  • how to use in your html view:
       <div class="form-group {{#if error 'name'}}has-error{{/if}}">
            <label for="name" class="control-label">Kelas Akun *</label>
            <input type="text" id="name" value="{{name}}" placeholder="Kelas Akun" class="form-control" autofocus="true">
            <span class="help-block">{{error "name"}}</span>
        </div>

1.3. meteoris:formatter

  • this Meteoris.Formatter extension used for formatting anything like date, datetime, currency etc
  • this require lepozepo:accounting and momentjs:moment to works
  • how to use in your html view:

enter image description here

{{meteoris_formatter 'the function name' firstParam secondParam}}
  • available function name:
    - date (date)
    - dateTime (date)
    - elapsedTime (date)
    - currency (value)
    - combodate (date)
    - combodateEmpty (date)
  • example date formatting
{{meteoris_formatter 'date' getCurrDate}}
Template.someTheme.helpers({
	getCurrDate: function(){
		return new Date();
	}
});

1.4. meteoris:grid-view

  • this Meteoris.GridView extension used for sorting your table header ascending or descending.

enter image description here

  • how to use in your html view:
<th id="btnSortName" class="{{meteoris_gridViewSortClass 'name'}}">Name</th>
  • how to use in your js events:
    Template.accountTypeIndex.events = {
        /* sorting by parameter */
        'click #btnSortName': function(e) {
            Meteoris.GridView.sort('name');
        },
    }

#2. Install Meteoris Theme Admin (Not Required But It will better to be installed)

This current version of meteoris only have 1 theme which is called meteoris:theme-admin. This theme using popular Admin LTE for it's UI, Click here for more info about Admin LTE.

To install this theme, simply add meteor package:

meteor add meteoris:theme-admin

How to use

  1. You can do general setting of this theme by targetting this url /meteoris/theme-admin/setting

enter image description here

  1. You can easily hook sidebar in html file:

a. In your app client folder, create hook folder and inside it, add this template code. b. You can change everything such as loggedin user, global search, and menus inside the template as you wish

<!-- In your app client folder, create hook folder and inside it, add this template code. -->
<!-- You can change everything such as loggedin user, global search, and menus inside the template as you wish -->

<template name="meteoris_themeAdmin_hookSidebar">
    <!-- Left side column. contains the logo and sidebar -->
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            {{#if currentUser}}
            <!-- Sidebar user panel -->
            <div class="user-panel">
                <div class="pull-left image">
                    <img src="/images/user.png" class="img-circle" alt="User Image">
                </div>
                <div class="pull-left info">
                    <p>{{currentUser.profile.name}}</p>
                    <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                </div>
            </div>
            {{/if}}
            <!--search form--> 
            <form action="#" method="get" class="sidebar-form">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="Search...">
                    <span class="input-group-btn">
                        <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
                    </span>
                </div>
            </form>
            <!--/.search form--> 
            <!-- sidebar menu: : style can be found in sidebar.less -->
            <ul class="sidebar-menu">
                <li class="header">MAIN NAVIGATION</li>
                <li><a href="/"><i class="fa fa-home"></i> Home</a></li>
                <!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
                <!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
                <li class="header">ADMIN AREA</li>                
                <li class="treeview">
                    <a href="#">
                        <i class="fa fa-gears"></i>
                        <i class="fa fa-angle-left pull-right"></i>
                        <span>Setting</span>                                
                    </a>
                    <ul class="treeview-menu">                        
                        <li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>                        
                        <li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>                        
                        <li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>                                         
                        <li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>                                                
                    </ul>
                </li>
                <!--{{/if}}-->
            </ul>
        </section>
        <!-- /.sidebar -->
    </aside>        
</template>
  1. You can hook navbar too in html file: a. In your app client folder, create hook folder and inside it, add this template code. b. You can change everything such as notification, current logged in user, user profile menu etc inside the template as you wish
<template name="meteoris_themeAdmin_hookNavbar">
    <div class="navbar-custom-menu">
        <ul class="nav navbar-nav">
            {{#if currentUser}}
            <!-- User Account: style can be found in dropdown.less -->
            <li class="dropdown user user-menu">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                    <img src="/images/user.png" class="user-image" alt="User Image">
                    <span class="hidden-xs">{{currentUser.profile.name}}</span>
                </a>
                <ul class="dropdown-menu">
                    <!-- User image -->
                    <li class="user-header">
                        <img src="/images/user.png" class="img-circle" alt="User Image">
                        <p>
                            {{currentUser.profile.name}}
                        </p>
                    </li>
                    <!-- Menu Footer-->
                    <li class="user-footer">
                        <div class="pull-left">
                            <a href="#" class="btn btn-default btn-flat">Profile</a>
                        </div>
                        <div class="pull-right">
                            <a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
                        </div>
                    </li>
                </ul>
            </li>
            {{else}}
            <li>
                <a href="/meteoris/user/login">Login</a>
            </li>
            {{/if}}
        </ul>
    </div>
</template>

c. add js file according to the template to get some event, and helper

var ctrl = new Meteoris.UserController();

Template.meteoris_themeAdmin_hookNavbar.events = {
    'click #btnLogout': function(){
        ctrl.logout();
    }
};

#3. Meteoris User (Not Required but it will be better to be installed)

  • NB: This package depends on Meteoris Theme Admin
  • The First Registered user will be assigned to admin group by default

You can use this main router:

'/meteoris/user', #to manage user as admin enter image description here

'/meteoris/user/login', #to logged in the user and '/meteoris/user/register', #to registering user enter image description here

'/meteoris/user/profile' #to updating current logged in user profile enter image description here

'/meteoris/user/settings', #to setting user oauth account enter image description here

#4. Install Meteoris Role (Not Required but it will be better to be installed)

enter image description here

How to use

1. Check whether current logged in user is in role or not in Collection/Server:

//you can use this code on collection-allow or on server
Meteoris.Role.userIsInRole(collection, action);

//example on collection:
MyCollection.allow({
    insert: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.POST);
    },
    update: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.PUT);
    },
    remove: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.DELETE);
    },
});

//example on router
var roleRoutes = FlowRouter.group({
    prefix: '/meteoris/role',
    name: 'meteoris_role',
    triggersEnter: [authenticating]
});

/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {    
    if (!Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.GET_ALL)){
        Meteoris.Flash.set("danger", "403 Unauthenticated");
        FlowRouter.go("/");
    }
}

2. Check whether current logged in user is in group or not in Collection/Server:

//you can use this code on collection-allow or on server
Meteoris.Role.userIsInGroup(groupName);

//example on collection:
MyCollection.allow({
    insert: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
    update: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
    remove: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
});

var roleRoutes = FlowRouter.group({
    prefix: '/meteoris/role',
    name: 'meteoris_role',
    triggersEnter: [authenticating]
});

/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {    
    if (!Meteoris.Role.userIsInGroup("user")){
        Meteoris.Flash.set("danger", "403 Unauthenticated");
        FlowRouter.go("/");
    }
}

3. Check whether current logged in user is in role or not in Client template:

//you can use this code on client template html
{{#if meteoris_roleUserIsInRole "collectionName" "actionName"}}
<!-- Your logic here -->
{{/if}}

//example on client template html:
{{#if meteoris_roleUserIsInRole "my-collection" "GET_ALL"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}

4. Check whether current logged in user is in group or not in Client template:

//you can use this code on client template html
{{#if meteoris_roleUserIsInGroup "groupName"}}
<!-- Your logic here -->
{{/if}}

//example on client template html:
{{#if meteoris_roleUserIsInGroup "admin"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}

Author: Meteoris
Source Code: https://github.com/meteoris/meteoris 
License: 

#node #javascript #mvc #framework 

What is GEEK

Buddha Community

KambojaJS: New Meteoris, A MVC and Modular Framework for Meteor
Desmond  Gerber

Desmond Gerber

1653737280

KambojaJS: New Meteoris, A MVC and Modular Framework for Meteor

WHAT IS METEORIS?

Meteoris is a Realtime MVC + Modular Javascript Framework based on Meteor 1.2.0. This is the latest version of Meteoris out there. In this version, Meteoris still doesn't have a code generator. If you prefer using the old version of meteoris, please use this version https://github.com/radiegtya/meteoris-v1.

QUICKSTART

1. Install Meteor, Create New Project & Download Required Packages

#install meteor
curl https://install.meteor.com/ | sh

#create new meteor project
meteor create my-meteoris-app

#the main module
meteor add meteoris:core

#another important module
meteor add meteoris:theme-admin
meteor add meteoris:user
meteor add meteoris:role

#remove meteor unused package
meteor remove insecure
meteor remove autopublish

2. Create hooked Navbar and Sidebar inside your "root/client/hook" folder

We can easily hook navbar and sidebar to customize our own sidebar and navbar although we are using meteoris:admin-theme template. The content of each template is using navbar and sidebar Admin LTE style. Make sure you are using correct theme name "meteoris_themeAdmin_hookNavbar" for sidebar, and "meteoris_themeAdmin_hookSidebar" for navbar.

<template name="meteoris_themeAdmin_hookNavbar">
    <div class="navbar-custom-menu">
        <ul class="nav navbar-nav">
            {{#if currentUser}}
            <!-- User Account: style can be found in dropdown.less -->
            <li class="dropdown user user-menu">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                    <img src="/images/user.png" class="user-image" alt="User Image">
                    <span class="hidden-xs">{{currentUser.profile.name}}</span>
                </a>
                <ul class="dropdown-menu">
                    <!-- User image -->
                    <li class="user-header">
                        <img src="/images/user.png" class="img-circle" alt="User Image">
                        <p>
                            {{currentUser.profile.name}}
                        </p>
                    </li>
                    <!-- Menu Footer-->
                    <li class="user-footer">
                        <div class="pull-left">
                            <a href="#" class="btn btn-default btn-flat">Profile</a>
                        </div>
                        <div class="pull-right">
                            <a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
                        </div>
                    </li>
                </ul>
            </li>
            {{else}}
            <li>
                <a href="/meteoris/user/login">Login</a>
            </li>
            {{/if}}
        </ul>
    </div>
</template>

"at root/client/hook/navbar.html"

var ctrl = new Meteoris.UserController();

Template.meteoris_themeAdmin_hookNavbar.events = {
    'click #btnLogout': function(){
        ctrl.logout();
    }
};

"at root/client/hook/navbar.js"

<template name="meteoris_themeAdmin_hookSidebar">
    <!-- Left side column. contains the logo and sidebar -->
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            {{#if currentUser}}
            <!-- Sidebar user panel -->
            <div class="user-panel">
                <div class="pull-left image">
                    <img src="/images/user.png" class="img-circle" alt="User Image">
                </div>
                <div class="pull-left info">
                    <p>{{currentUser.profile.name}}</p>
                    <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                </div>
            </div>
            {{/if}}
            <!--search form--> 
            <form action="#" method="get" class="sidebar-form">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="Search...">
                    <span class="input-group-btn">
                        <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
                    </span>
                </div>
            </form>
            <!--/.search form--> 
            <!-- sidebar menu: : style can be found in sidebar.less -->
            <ul class="sidebar-menu">
                <li class="header">MAIN NAVIGATION</li>
                <li><a href="/"><i class="fa fa-home"></i> Home</a></li>
                <!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
                <!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
                <li class="header">ADMIN AREA</li>                
                <li class="treeview">
                    <a href="#">
                        <i class="fa fa-gears"></i>
                        <i class="fa fa-angle-left pull-right"></i>
                        <span>Setting</span>                                
                    </a>
                    <ul class="treeview-menu">                        
                        <li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>                        
                        <li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>                        
                        <li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>                                         
                        <li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>                                                
                    </ul>
                </li>
                <!--{{/if}}-->
            </ul>
        </section>
        <!-- /.sidebar -->
    </aside>        
</template>

"at root/client/hook/sidebar.html"

3. Creating Home/Site Page

Meteoris use simple MVC or MVVM + Modular paradigm to structuring app. Please use this standard structure to achieve best result when using meteoris.

3.1. Folder Structure

root/
  meteorusernameorgroup:module/
	client/             # Client folder
	   views/           # Views for html/js files
	lib/                # Both Access folder
	   collections/     # Collections folder
	   controllers/     # Controllers Folder
	   router.js        # Router js file
	server/             # Server folder			   

3.2. Router Meteoris using Kadira Flow Router to linking between pages. Because we are using modular technique, assume that we are using my meteor account called "radiegtya" and using module name called "site". So we should make folder under root folder called "radiegtya:site". To use modular router, simply follow this step:

  • create router file on "root/radiegtya:site/lib/router.js", and type this code
/**
create group routes, so every router has prefix radiegtya
*/
var groupRoutes = FlowRouter.group({
    prefix: '/radiegtya',
    name: 'radiegtya',
});

/**
create the main router called site, and use BlazeLayout render "meteoris_themeAdminMain" from metoris:theme-admin package, and accessing template called "radiegtya_siteIndex"
*/
groupRoutes.route('/site', {
    action: function() {
        BlazeLayout.render('meteoris_themeAdminMain', {content: "radiegtya_siteIndex"});
    },   
});
  • We are not yet able to use this router, but once you have created the views, you can access this page by calling this route:
localhost:3000/radiegtya/site

3.3. Creating Controller for Site Controller actually just a method to be called inside your template js, and this will make your code more modular and readable.

  • Create controller file on "root/radiegtya:site/lib/controller/SiteController.js"
/*
create a namespace called Radiegtya.SiteController
*/
Namespace('Radiegtya.SiteController');

/**
Create controller which extends Meteoris Controller
*/
Radiegtya.SiteController = Meteoris.Controller.extend({
	constructor : function() {
            // set default counter at constructor
            Session.setDefault('counter', 0);
        },
        /* passing data to index helpers template */
	index: function() {			        
		//return some value, to be passed on index.js
		return {
		    counter: this.getCounter(),
			myName: "Ega Radiegtya",
			myHobby: "Drinking Coffee"
		};
	},
	getCounter: function(){
		return Session.get("counter");
	},
	setCounter: function(counter){
		Session.set('counter', this.getCounter() + 1);
	}
});

3.4. Creating Views Page for Site

  • create views index file on "root/radiegtya:site/client/views/index.html". Look at the template naming convention, it use "meteorusername_moduleAction" namespacing, so for this views we are gonna use "radiegtya_siteIndex". Which is "radiegtya" for meteor username, "site" for the module name, and "Index" in camel case after site as action name.
<template name="radiegtya_siteIndex">
	<div class="content">
		<div class="box">
			<div class="box-body">
				<button>Click Me</button>
				<p>
				You've pressed the button {{counter}} times.
				</p>
			</div>
		</div>
	</div>
</template>

because we are installing meteoris:theme-admin, you can use adminLTE styling and html inside your views html file. We are using meteor example to make You more familiar with the code.

  • Don't forget to add the js file for the index. Create this file on "root/radiegtya:site/client/views/index.js"
var ctrl = new Radiegtya.SiteController();

/**
In the template helper section we are using index() method to get object return value from controller. It's because index was the action and also the file name suffix. This structure will make You easier to get jobs done, when your team getting bigger and the code getting bigger.
*/
Template.radiegtya_siteIndex.helpers({
	myName: function () {
		return ctrl.index().myName;
	},
	myHobby: function () {
		return ctrl.index().myHobby;
	},	
    counter: function () {
      return ctrl.index().counter;
    }
  });

/**
in the template events, we don't need to use index() method to call any action. Because it just simply method calling through controller.
*/
Template.radiegtya_siteIndex.events({
    'click button': function () {
      //increment the counter when button is clicked
      ctrl.setCounter();      
    }
});

Now finally access this route to check your apps.

localhost:3000/radiegtya/site

enter image description here

Awesome! We are successfully creating our simple app in MVC and Modular way with very easy setup. Ofc with amazing template which is reusable. You can also use this code to create a meteor package easily.

3.5. Creating Collection You can use aldeed:collection2, aldeed:simple-schema, and dburles:collection-helpers in our Meteoris collection. Future explanation will be comming soon. ======== COMING SOON =========

3.6. Creating Server You can use reywood:publish-composite here. Future explanation coming soon. ======== COMING SOON =========

3.7. Using Meteoris Plugin For now You can refer to the below this Quick Start article.

====================================================================================

#1. INSTALLATION

meteor add meteoris:core

it will also installing it's dependencies, which are:

1.1. meteoris:flash

Meteoris Package to show Flash/Toast Error/Success in your bottom right screen.

enter image description here

how to use in your js file:

//set flash message example
Meteoris.Flash.set('success', 'Data Successfully added');
Meteoris.Flash.set('danger', 'Data Failed to be added');

how to use in your html file:

<!-- Simply place this code on your html view anywhere -->
{{> meteoris_flash}}

1.2. meteoris:form-validation

Meteoris package to validate form easily. This Meteoris.FormValidation extension depends on collection2 and simpleschema:

enter image description here

AccountType = new Mongo.Collection("accountType");

var schemas = new SimpleSchema({
    accountClassId: {
        type: String,
        label: "Kelas Akun",
    },    
});

AccountType.attachSchema(schemas);
  • how to use in your js helper:
    /* show error message on view */
    error: function(field) {
        return Meteoris.FormValidation.error(YourCollectionName, field);
    },
  • how to use in your html view:
       <div class="form-group {{#if error 'name'}}has-error{{/if}}">
            <label for="name" class="control-label">Kelas Akun *</label>
            <input type="text" id="name" value="{{name}}" placeholder="Kelas Akun" class="form-control" autofocus="true">
            <span class="help-block">{{error "name"}}</span>
        </div>

1.3. meteoris:formatter

  • this Meteoris.Formatter extension used for formatting anything like date, datetime, currency etc
  • this require lepozepo:accounting and momentjs:moment to works
  • how to use in your html view:

enter image description here

{{meteoris_formatter 'the function name' firstParam secondParam}}
  • available function name:
    - date (date)
    - dateTime (date)
    - elapsedTime (date)
    - currency (value)
    - combodate (date)
    - combodateEmpty (date)
  • example date formatting
{{meteoris_formatter 'date' getCurrDate}}
Template.someTheme.helpers({
	getCurrDate: function(){
		return new Date();
	}
});

1.4. meteoris:grid-view

  • this Meteoris.GridView extension used for sorting your table header ascending or descending.

enter image description here

  • how to use in your html view:
<th id="btnSortName" class="{{meteoris_gridViewSortClass 'name'}}">Name</th>
  • how to use in your js events:
    Template.accountTypeIndex.events = {
        /* sorting by parameter */
        'click #btnSortName': function(e) {
            Meteoris.GridView.sort('name');
        },
    }

#2. Install Meteoris Theme Admin (Not Required But It will better to be installed)

This current version of meteoris only have 1 theme which is called meteoris:theme-admin. This theme using popular Admin LTE for it's UI, Click here for more info about Admin LTE.

To install this theme, simply add meteor package:

meteor add meteoris:theme-admin

How to use

  1. You can do general setting of this theme by targetting this url /meteoris/theme-admin/setting

enter image description here

  1. You can easily hook sidebar in html file:

a. In your app client folder, create hook folder and inside it, add this template code. b. You can change everything such as loggedin user, global search, and menus inside the template as you wish

<!-- In your app client folder, create hook folder and inside it, add this template code. -->
<!-- You can change everything such as loggedin user, global search, and menus inside the template as you wish -->

<template name="meteoris_themeAdmin_hookSidebar">
    <!-- Left side column. contains the logo and sidebar -->
    <aside class="main-sidebar">
        <!-- sidebar: style can be found in sidebar.less -->
        <section class="sidebar">
            {{#if currentUser}}
            <!-- Sidebar user panel -->
            <div class="user-panel">
                <div class="pull-left image">
                    <img src="/images/user.png" class="img-circle" alt="User Image">
                </div>
                <div class="pull-left info">
                    <p>{{currentUser.profile.name}}</p>
                    <a href="#"><i class="fa fa-circle text-success"></i> Online</a>
                </div>
            </div>
            {{/if}}
            <!--search form--> 
            <form action="#" method="get" class="sidebar-form">
                <div class="input-group">
                    <input type="text" name="q" class="form-control" placeholder="Search...">
                    <span class="input-group-btn">
                        <button type="submit" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i></button>
                    </span>
                </div>
            </form>
            <!--/.search form--> 
            <!-- sidebar menu: : style can be found in sidebar.less -->
            <ul class="sidebar-menu">
                <li class="header">MAIN NAVIGATION</li>
                <li><a href="/"><i class="fa fa-home"></i> Home</a></li>
                <!--Uncomment this if you want to hide this menu using the power of meteoris:role-->
                <!--{{#if meteoris_roleUserIsInGroup "admin"}}-->
                <li class="header">ADMIN AREA</li>                
                <li class="treeview">
                    <a href="#">
                        <i class="fa fa-gears"></i>
                        <i class="fa fa-angle-left pull-right"></i>
                        <span>Setting</span>                                
                    </a>
                    <ul class="treeview-menu">                        
                        <li><a href="/meteoris/theme-admin/setting"><i class="fa fa-laptop"></i> Theme Admin Setting</a></li>                        
                        <li><a href="/meteoris/user"><i class="fa fa-users"></i> Users Management</a></li>                        
                        <li><a href="/meteoris/user/settings"><i class="fa fa-user"></i> User Settings</a></li>                                         
                        <li><a href="/meteoris/role"><i class="fa fa-flag-o"></i> Role Management</a></li>                                                
                    </ul>
                </li>
                <!--{{/if}}-->
            </ul>
        </section>
        <!-- /.sidebar -->
    </aside>        
</template>
  1. You can hook navbar too in html file: a. In your app client folder, create hook folder and inside it, add this template code. b. You can change everything such as notification, current logged in user, user profile menu etc inside the template as you wish
<template name="meteoris_themeAdmin_hookNavbar">
    <div class="navbar-custom-menu">
        <ul class="nav navbar-nav">
            {{#if currentUser}}
            <!-- User Account: style can be found in dropdown.less -->
            <li class="dropdown user user-menu">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                    <img src="/images/user.png" class="user-image" alt="User Image">
                    <span class="hidden-xs">{{currentUser.profile.name}}</span>
                </a>
                <ul class="dropdown-menu">
                    <!-- User image -->
                    <li class="user-header">
                        <img src="/images/user.png" class="img-circle" alt="User Image">
                        <p>
                            {{currentUser.profile.name}}
                        </p>
                    </li>
                    <!-- Menu Footer-->
                    <li class="user-footer">
                        <div class="pull-left">
                            <a href="#" class="btn btn-default btn-flat">Profile</a>
                        </div>
                        <div class="pull-right">
                            <a href="#" id="btnLogout" class="btn btn-default btn-flat">Logout</a>
                        </div>
                    </li>
                </ul>
            </li>
            {{else}}
            <li>
                <a href="/meteoris/user/login">Login</a>
            </li>
            {{/if}}
        </ul>
    </div>
</template>

c. add js file according to the template to get some event, and helper

var ctrl = new Meteoris.UserController();

Template.meteoris_themeAdmin_hookNavbar.events = {
    'click #btnLogout': function(){
        ctrl.logout();
    }
};

#3. Meteoris User (Not Required but it will be better to be installed)

  • NB: This package depends on Meteoris Theme Admin
  • The First Registered user will be assigned to admin group by default

You can use this main router:

'/meteoris/user', #to manage user as admin enter image description here

'/meteoris/user/login', #to logged in the user and '/meteoris/user/register', #to registering user enter image description here

'/meteoris/user/profile' #to updating current logged in user profile enter image description here

'/meteoris/user/settings', #to setting user oauth account enter image description here

#4. Install Meteoris Role (Not Required but it will be better to be installed)

enter image description here

How to use

1. Check whether current logged in user is in role or not in Collection/Server:

//you can use this code on collection-allow or on server
Meteoris.Role.userIsInRole(collection, action);

//example on collection:
MyCollection.allow({
    insert: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.POST);
    },
    update: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.PUT);
    },
    remove: function(userId, doc) {
        return Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.DELETE);
    },
});

//example on router
var roleRoutes = FlowRouter.group({
    prefix: '/meteoris/role',
    name: 'meteoris_role',
    triggersEnter: [authenticating]
});

/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {    
    if (!Meteoris.Role.userIsInRole("my-collection", Meteoris.Role.GET_ALL)){
        Meteoris.Flash.set("danger", "403 Unauthenticated");
        FlowRouter.go("/");
    }
}

2. Check whether current logged in user is in group or not in Collection/Server:

//you can use this code on collection-allow or on server
Meteoris.Role.userIsInGroup(groupName);

//example on collection:
MyCollection.allow({
    insert: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
    update: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
    remove: function(userId, doc) {
        return Meteoris.Role.userIsInGroup("admin");
    },
});

var roleRoutes = FlowRouter.group({
    prefix: '/meteoris/role',
    name: 'meteoris_role',
    triggersEnter: [authenticating]
});

/* router level validation, only allow user with group "admin" to access this page */
function authenticating() {    
    if (!Meteoris.Role.userIsInGroup("user")){
        Meteoris.Flash.set("danger", "403 Unauthenticated");
        FlowRouter.go("/");
    }
}

3. Check whether current logged in user is in role or not in Client template:

//you can use this code on client template html
{{#if meteoris_roleUserIsInRole "collectionName" "actionName"}}
<!-- Your logic here -->
{{/if}}

//example on client template html:
{{#if meteoris_roleUserIsInRole "my-collection" "GET_ALL"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}

4. Check whether current logged in user is in group or not in Client template:

//you can use this code on client template html
{{#if meteoris_roleUserIsInGroup "groupName"}}
<!-- Your logic here -->
{{/if}}

//example on client template html:
{{#if meteoris_roleUserIsInGroup "admin"}}
<li><a href="/my-collection"><i class="fa fa-flag-o"></i> My Collection Menu</a></li>
{{/if}}

Author: Meteoris
Source Code: https://github.com/meteoris/meteoris 
License: 

#node #javascript #mvc #framework 

navin prakash

1607084960

MVC Framework - Introduction

The Model-View-Controller (MVC) is an architectural style dividing an application into three main system elements: the model, the view, and the controller. Every one of these elements is designed to manage particular aspects of an application’s growth. To build scalable and extensible projects, MVC is one of the most commonly used industry-standard web design platforms.
MVC Elements
Following are the elements of MVC:
Model
All the data-related logic that the user works with corresponds to the Model part. It can represent either the data that is being transmitted between the elements of the View and Controller or some other data relevant to business logic. A customer object, for example, retrieves customer information from the database, manipulates it and updates its data back to the database, or utilizes this for information rendering.
View
For all of the application’s UI logic, the View element has been used. For example, all the UI elements such as text boxes, dropdowns, etc. That the final user communicates with will be included in the Customer’s perspective.
Controller
In order to manage all business rules and incoming requests, controllers serve as an interface between the Model And View elements, modify data using the Model component, and communicate with the Views to make the final performance. For example, the Customer Controller will handle all the Customer View interactions and inputs, and the database will be modified using the Customer Model. To display customer information, the same controller will be used.
ASP.NET MVC:
ASP.NET supports three main growth models: Web sites, Web Forms and MVC (Model View Controller).
ASP.NET MVC Features
ASP.NET MVC provides the following characteristics :

  • Ideal for designing applications that are complex but lightweight.
  • It offers an expandable and pluggable system that can be quickly replaced and customized. If you do not want to use the built-in Razor or ASPX View Engine, for instance, you can use some other third-party display engines or even customize existing ones.
  • Using the application’s elements-based architecture by logically breaking this into elements of the Organization, Display, and Controller. This allows developers to control the scope and focus on specific elements of large-scale projects.
  • The MVC structure enhances the app’s test-driven growth and testability since all elements can be programmed utilizing mock objects based on the interface. Hence, ASP.NET MVC Platform is suitable for Projects with a wide team of web designers.
  • Supports all the comprehensive ASP.NET features currently available, such as Authorization and Authentication, Master Pages, Data Linking, User Controls, Memberships, ASP.NET Routing, etc.
  • Don’t use View State definition (which is present in ASP.NET). This helps to create lightweight apps and allows the designers full power.
    You should also recognize the MVC System as a major structure built on top of ASP.NET that offers a wide range of added features focused on component-based creation and checking. MVC Training in Chennai is the best for freshers and professional workers. FITA is the NO.1 Training Institute to learn MVC Course in Chennai with certification. This Certification very usefu to get a job in the IT industry.

#mvc course in chennai #mvc #mvc training in chennai #mvc training #mvc course

Justen  Hintz

Justen Hintz

1663559281

To-do List App with HTML, CSS and JavaScript

Learn how to create a to-do list app with local storage using HTML, CSS and JavaScript. Build a Todo list application with HTML, CSS and JavaScript. Learn the basics to JavaScript along with some more advanced features such as LocalStorage for saving data to the browser.

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>To Do List With Local Storage</title>
    <!-- Font Awesome Icons -->
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
    />
    <!-- Google Fonts -->
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap"
      rel="stylesheet"
    />
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="container">
      <div id="new-task">
        <input type="text" placeholder="Enter The Task Here..." />
        <button id="push">Add</button>
      </div>
      <div id="tasks"></div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
  </body>
</html>

CSS:

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}
body {
  background-color: #0b87ff;
}
.container {
  width: 90%;
  max-width: 34em;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}
#new-task {
  position: relative;
  background-color: #ffffff;
  padding: 1.8em 1.25em;
  border-radius: 0.3em;
  box-shadow: 0 1.25em 1.8em rgba(1, 24, 48, 0.15);
  display: grid;
  grid-template-columns: 9fr 3fr;
  gap: 1em;
}
#new-task input {
  font-family: "Poppins", sans-serif;
  font-size: 1em;
  border: none;
  border-bottom: 2px solid #d1d3d4;
  padding: 0.8em 0.5em;
  color: #111111;
  font-weight: 500;
}
#new-task input:focus {
  outline: none;
  border-color: #0b87ff;
}
#new-task button {
  font-family: "Poppins", sans-serif;
  font-weight: 500;
  font-size: 1em;
  background-color: #0b87ff;
  color: #ffffff;
  outline: none;
  border: none;
  border-radius: 0.3em;
  cursor: pointer;
}
#tasks {
  background-color: #ffffff;
  position: relative;
  padding: 1.8em 1.25em;
  margin-top: 3.8em;
  width: 100%;
  box-shadow: 0 1.25em 1.8em rgba(1, 24, 48, 0.15);
  border-radius: 0.6em;
}
.task {
  background-color: #ffffff;
  padding: 0.3em 0.6em;
  margin-top: 0.6em;
  display: flex;
  align-items: center;
  border-bottom: 2px solid #d1d3d4;
  cursor: pointer;
}
.task span {
  font-family: "Poppins", sans-serif;
  font-size: 0.9em;
  font-weight: 400;
}
.task button {
  color: #ffffff;
  padding: 0.8em 0;
  width: 2.8em;
  border-radius: 0.3em;
  border: none;
  outline: none;
  cursor: pointer;
}
.delete {
  background-color: #fb3b3b;
}
.edit {
  background-color: #0b87ff;
  margin-left: auto;
  margin-right: 3em;
}
.completed {
  text-decoration: line-through;
}

Javascript:

//Initial References
const newTaskInput = document.querySelector("#new-task input");
const tasksDiv = document.querySelector("#tasks");
let deleteTasks, editTasks, tasks;
let updateNote = "";
let count;

//Function on window load
window.onload = () => {
  updateNote = "";
  count = Object.keys(localStorage).length;
  displayTasks();
};

//Function to Display The Tasks
const displayTasks = () => {
  if (Object.keys(localStorage).length > 0) {
    tasksDiv.style.display = "inline-block";
  } else {
    tasksDiv.style.display = "none";
  }

  //Clear the tasks
  tasksDiv.innerHTML = "";

  //Fetch All The Keys in local storage
  let tasks = Object.keys(localStorage);
  tasks = tasks.sort();

  for (let key of tasks) {
    let classValue = "";

    //Get all values
    let value = localStorage.getItem(key);
    let taskInnerDiv = document.createElement("div");
    taskInnerDiv.classList.add("task");
    taskInnerDiv.setAttribute("id", key);
    taskInnerDiv.innerHTML = `<span id="taskname">${key.split("_")[1]}</span>`;
    //localstorage would store boolean as string so we parse it to boolean back
    let editButton = document.createElement("button");
    editButton.classList.add("edit");
    editButton.innerHTML = `<i class="fa-solid fa-pen-to-square"></i>`;
    if (!JSON.parse(value)) {
      editButton.style.visibility = "visible";
    } else {
      editButton.style.visibility = "hidden";
      taskInnerDiv.classList.add("completed");
    }
    taskInnerDiv.appendChild(editButton);
    taskInnerDiv.innerHTML += `<button class="delete"><i class="fa-solid fa-trash"></i></button>`;
    tasksDiv.appendChild(taskInnerDiv);
  }

  //tasks completed
  tasks = document.querySelectorAll(".task");
  tasks.forEach((element, index) => {
    element.onclick = () => {
      //local storage update
      if (element.classList.contains("completed")) {
        updateStorage(element.id.split("_")[0], element.innerText, false);
      } else {
        updateStorage(element.id.split("_")[0], element.innerText, true);
      }
    };
  });

  //Edit Tasks
  editTasks = document.getElementsByClassName("edit");
  Array.from(editTasks).forEach((element, index) => {
    element.addEventListener("click", (e) => {
      //Stop propogation to outer elements (if removed when we click delete eventually rhw click will move to parent)
      e.stopPropagation();
      //disable other edit buttons when one task is being edited
      disableButtons(true);
      //update input value and remove div
      let parent = element.parentElement;
      newTaskInput.value = parent.querySelector("#taskname").innerText;
      //set updateNote to the task that is being edited
      updateNote = parent.id;
      //remove task
      parent.remove();
    });
  });

  //Delete Tasks
  deleteTasks = document.getElementsByClassName("delete");
  Array.from(deleteTasks).forEach((element, index) => {
    element.addEventListener("click", (e) => {
      e.stopPropagation();
      //Delete from local storage and remove div
      let parent = element.parentElement;
      removeTask(parent.id);
      parent.remove();
      count -= 1;
    });
  });
};

//Disable Edit Button
const disableButtons = (bool) => {
  let editButtons = document.getElementsByClassName("edit");
  Array.from(editButtons).forEach((element) => {
    element.disabled = bool;
  });
};

//Remove Task from local storage
const removeTask = (taskValue) => {
  localStorage.removeItem(taskValue);
  displayTasks();
};

//Add tasks to local storage
const updateStorage = (index, taskValue, completed) => {
  localStorage.setItem(`${index}_${taskValue}`, completed);
  displayTasks();
};

//Function To Add New Task
document.querySelector("#push").addEventListener("click", () => {
  //Enable the edit button
  disableButtons(false);
  if (newTaskInput.value.length == 0) {
    alert("Please Enter A Task");
  } else {
    //Store locally and display from local storage
    if (updateNote == "") {
      //new task
      updateStorage(count, newTaskInput.value, false);
    } else {
      //update task
      let existingCount = updateNote.split("_")[0];
      removeTask(updateNote);
      updateStorage(existingCount, newTaskInput.value, false);
      updateNote = "";
    }
    count += 1;
    newTaskInput.value = "";
  }
});

Related Videos

Build a Todo list app in HTML, CSS & JavaScript | JavaScript for Beginners tutorial

Build a Todo List App in HTML, CSS & JavaScript with LocalStorage | JavaScript for Beginners

To Do List using HTML CSS JavaScript | To Do List JavaScript

Create A Todo List App in HTML CSS & JavaScript | Todo App in JavaScript

#html #css #javascript

Best Android Mobile App Development Frameworks

Are you looking for the best Android app development frameworks? Get the best Android app development frameworks that help to build the top-notch Android mobile app.

For more info:
Website: https://www.appcluesinfotech.com/
Email: info@appcluesinfotech.com
Call: +1-978-309-9910

#best android mobile app development frameworks #top mobile app development frameworks #android app development frameworks #top frameworks for android app development #most popular android app development frameworks #app development frameworks

Obie  Beier

Obie Beier

1625660460

Learn MVC 5 & MVC Core with Angular

Learn MVC 5 & MVC Core with Angular @ 1990INR/30USD
https://www.questpond.com/angular-with-mvc-core-combo-package/cid61

Following the Syllabus covered in this Package:
*Learn Angular 7.X, 8.X Step By Step.
*Angular Interview Q & A.
*Learn MVC 5 in 2 days.
*Learn MVC core in 4 hours.
*MVC Core Training Recording.

For more details contact questpond@questpond.com OR call +919967590707-9619842789.

#mvc 5 & mvc #angular #mvc #mvc 5