Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Purpose:

The purpose of this document is to highlight the guidelines for building or extending an e-Business control.

Prerequisite learning needed for building new control.

3rd Party control files.

  • fullcalender.min.js
  • fullcalendar.css
  • alertify-1.0.6.js

Control level guidelines with examples.

  • A control should have one javascript file and one HTML template file with the same name. 
    exampleExample: html/BillingShippingAddress.html and js/BillingShippingAddress.js

  • HTML template file should have plain HTML tags with knockout attributes

    example

    Example


    <div class

    Code Block
    languagexml
    <div class="form-group">

    
    <label class="caption">Username</label>

    
    <input class="form-control" type="email" placeholder="Username / Email" required autofocus="" data-bind="value: userName>

    
    </div>
  • A control's name should unique and meaningful and should not duplicate.
    exampleExample: BillingShippingAddress.html and BillingShippingAddress.js

  • A javascript variable will be created that will act as a collection for all of the controls objects. 
    example Example : var  var eb_billingShippingAddress = eb_billingShippingAddress || {};

  • Control's properties, functions and methods name should start with came camel case.
    exampleExample: productCatalogPage productCatalogPage

  • Any object at the collection level should be generic to all instances of that control. Instance-specific information should live at the model level. 
    SitePath, TemplatePath, and ServicePath would be fixed properties for each control. These variables should be prefixed with an eb_prefix so that it does not collide with other JavaScript systems.

    example

    Example : 
     

    Code Block
    languagejs
    eb_billingShippingAddress.SitePath = eb_Config.SitePath;

    
    eb_billingShippingAddress.TemplatePath = "html/BillingShippingAddress.html";

    
    eb_billingShippingAddress.ServicePath = eb_Config.ServicePath;

     

  • The Path of the HTML template should mirror that of the path to the JS.

    example:

    Example: 

    Code Block
    languagejs
    eb_billingShippingAddress.TemplatePath = "html/BillingShippingAddress.html";
  • Each model's properties / field should be defined camel case and assign to ko.observable / ko.observableArray / ko.computed based on logic. 

    example

    Example

    Code Block
    languagejs
       var _that = this;

    
     _that.domElement = options.domElement;

    
    _that.showError = ko.observable(0);

    
    _that.errorMessage = ko.observable();

    
    _that.showSuccess = ko.observable(0);

    
    _that.successMessage = ko.observable();

    
    _that.billingAddress = ko.observableArray();
  • Should not use 'this' object directly in function. Create local variable var _self = this; and use it.
  • Each model's function's functions name should be meaningful and scope should be model's context.
    example:Example:

    Code Block
    languagejs
    _that.toggleShipping = function () {

    
    	_that.shippingAddressCollapse(!_that.shippingAddressCollapse());

    
    };

...

  • If there is more than one model for a control, a collection called models will be added to the control collection.
  • Sitewide settings such as the dom, service data, template path and dependent objects etc. will be passed into the control's javascript collection at the time of model creation.

    example

    Example

    Code Block
    languagejs
    eb_billingShippingAddress.model = function (options) {

    
    	var _that = this;........}
  •  A render function should exist on each control.
    • Its job is to grab the template and insert it into a dom element that is passed into the function.
    • It should accept a user-supplied template in the place of the default template.

exampleExample: 

 

Code Block
languagejs
eb_billingShippingAddress.render = function (options) {

...


	var defer = jQuery.Deferred();

...



	if (!options) {

...


		throw { type: "argument_null", message: "An object with values in the templatePath and domElement properties is required.", stack: Error().stack };

...


	}

	if (!options.templatePath) {

...


		var finalPath = eb_billingShippingAddress.SitePath + eb_billingShippingAddress.TemplatePath;

...


		options.templatePath = finalPath;

...


	}

	if (!options.domElement) {

...


		throw { type: "argument_mismatch", message: 'Missing domElement. The object passed in must have a domElement property with a non-empty DOM object.', stack: Error().stack };

...


	}

	$.get(options.templatePath).done(function (data) {

...


		options.domElement.innerHTML = data;

...


		defer.resolve(data);

...


	}).fail(defer.reject);

...


	return defer.promise();

...


};

...

  • GET service call method should be control leve level with parameters and should have deferred object handling.
    exampleExample: 

     

    Code Block
    languagejs
    eb_billingShippingAddress.createAddressRecord = function (data, personId) {

    
    	var defer = jQuery.Deferred();

    
    	console.info('create address record...');
    
    
    	if (!personId || personId <= 0) {

    
    		throw { type: "argument_null", message: "personId property is required.", stack: Error().stack };

    
    	}

    
    	if (!data) {

    
    		throw { data: "argument_null", message: "data property is required.", stack: Error().stack };

    
    	}

    
    	var service = eb_billingShippingAddress.newAddressService.replace("{personId}", personId);
    
    
    	$.ajax({

    
    		url: service,

    
    		crossDomain: true,

    
    		type: "POST",

    
    		data: data,

    
    		xhrFields: {

    
    			withCredentials: true

    }
    
    		}
    	}).done(function (result) {

    
    		defer.resolve(result);

    
    	}).fail(defer.reject);

    
    	return defer.promise();

    
    };
    
    
  • PATCH service call method should be control leve level with parameters and should have deferred object handling.
    exampleExample: 

     eb_

    Code Block
    languagejs
    eb_billingShippingAddress.updateProfileAddressRecord = function (data, addressName, personId) {

    
    	var defer = jQuery.Deferred();

    
    	if (!personId || personId <= 0) {

    
    		throw { type: "argument_null", message: "personId property is required.", stack: Error().stack };

    }if
    
    	}
    
    	if (!addressName) {

    
    		throw { type: "argument_null", message: "addressName property is required.", stack: Error().stack };

    }if
    
    	}
    
    	if (!data) {

    
    		throw { data: "argument_null", message: "data property is required.", stack: Error().stack };

    }
    
    	}
    
    	console.info('update address...');

    
    	var service = eb_billingShippingAddress.updateProfileAddressService.replace("{personId}", personId).replace("{addressName}", addressName);

    
    	$.ajax({

    
    		url: service,

    
    		type: "PATCH",

    
    		contentType: "application/json",

     
    		data: JSON.stringify(data),

    
    		xhrFields: {

    
    			withCredentials: true

    }
    
    		}
    	}).done(function (result) {

    
    		defer.resolve(result);

    
    	}).fail(defer.reject);

    
    	return defer.promise();

    
    };
    
    
  • POST service call method should be control leve control level with parameters and should have deferred object handling.
    exampleExample: 

     

    Code Block
    languagejs
    eb_billingShippingAddress.createAddressRecord = function (data, personId) {

    
    	var defer = jQuery.Deferred();

    
    	console.info('create address record...');
    
    
    	if (!personId || personId <= 0) {

    
    		throw { type: "argument_null", message: "personId property is required.", stack: Error().stack };

    
    	}

    
    	if (!data) {

    
    		throw { data: "argument_null", message: "data property is required.", stack: Error().stack };

    
    	}

    
    	var service = eb_billingShippingAddress.newAddressService.replace("{personId}", personId);
    
    
    	$.ajax({

    
    		url: service,

    
    		crossDomain: true,

    
    		type: "POST",

    
    		data: data,

    
    		xhrFields: {

    
    			withCredentials: true

    }
    
    		}
    	}).done(function (result) {

    
    		defer.resolve(result);

    
    	}).fail(defer.reject);

    
    	return defer.promise();

    
    };
  • DELETE service call method should be control leve control level with parameters and should have deferred object handling.
    exampleExample:

     

    Code Block
    languagejs
    eb_billingShippingAddress.deletePersonAddressRecord = function (addressName, personId) {

    
    	var defer = jQuery.Deferred();

    
    	if (!personId || personId <= 0) {

    
    		throw { type: "argument_null", message: "personId property is required.", stack: Error().stack };

    }if
    
    	}
    
    	if (!addressName) {

    
    		throw { type: "argument_null", message: "addressName property is required.", stack: Error().stack };

    }
    
    	}
    
    	console.info('delete address...');

    
    	var service = eb_billingShippingAddress.deletePersonAddressService.replace("{personId}", personId).replace("{addressName}", addressName);
    
    
    	$.ajax({

    
    		url: service,

    
    		type: "DELETE",

    
    		xhrFields: {

    
    			withCredentials: true

    }
    
    		}
    	}).done(function (result) {

    
    		defer.resolve(result);

    
    	}).fail(defer.reject);

    
    	return defer.promise();

    
    };

     

  • Each service call should have handled with Jquery Deferred object with proper use of resolve(), reject() and promise() methods.

  • Service's fails case should be handled properly and write an appropriate meaningful error message based on the control requirements. We have handled three different way of error messages.  
    • Error log in browsers console : Console.info("error message") and  Console.error("error message"); 
    • Control level predefined error messages under the knownResponses method :  _that.errorMessage(eb_billingShippingAddress.knownResponses[2].message);
    • Error message from service side: _that.errorMessage(data.responseJSON.message);

  • Knockout validations: https://github.com/Knockout-Contrib/Knockout-Validation

  • The control will know the default relative path to its HTML and it will be declared in a variable in the collection.
  • YUIDoc comments should be used and should be meaningful information that developers can use to understand what a function is doing.
  • Instance initiation should not happen at the control level.
  • References to JS objects outside of the scope of the control should be avoided.
  • It should only take 1 call to the server to get all of the initial data to show to the user.
  • Controls will be loaded asynchronously by the browser in whatever order the browser chooses if not dependent with each other.

Page level guidelines with examples.

  • References to all of the Javascript and CSS needed should be loaded at the page level. It should under the head tag.

    example

    Example

    Code Block
    languagexml
    <head>

    
    <meta charset="UTF-8">

    
    <meta name="viewport" content="width=device-width, initial-scale=1">

    
    <title>Billing and Shipping Address</title>

    
    <script src="js/3rdParty/jquery-3.2.1.min.js"></script>

    
    <script src="js/3rdParty/knockout-3.4.2.js"></script>

    
    <script src="js/3rdParty/bootstrap.min.js"></script>

    
    <script src="js/3rdParty/knockout.validation.min.js"></script>

    
    <!--Solved icons issue-->

    
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

    
    <link rel="stylesheet" type="text/css" href="css/eb6.css" />

    
    <link rel="stylesheet" type="text/css" href="css/responsive.css" />

    
    <script src="js/configuration/ebConfig.js"></script>

    
    <script src="js/UserContext.js"></script>

    
    <script src="js/ShoppingCart.js"></script>

    
    <script src="js/PaymentSummary.js"></script>

    
    <script src="js/BillingShippingAddress.js"></script>

    
    </head>
  • Need to define div element with ID attribute for loading control on the html page. If page having two controls then add two coloum column div with ID on page.
    exampleExample: 
     

    Code Block
    languagexml
    <div class="ebBody ebWrapper">

    
    	<div class="ebusiness-main-container ebClear">

    
    	<!--This div where the Billing and Shipping Address will come-->

    
    		<div class="col-md-8">

    
    			<div id="BillingShippingAddress"></div>

    
    		</div>
    
    
    		<!--This div where payment summary will come-->

    
    		<div class="col-md-4">

    
    			<div id="paymentSummary"></div>

    
    		</div>

    
    	</div>

    
    </div>

     

  • JS Code should write <script write <script type="text/javascript"> $(document).ready (function () {}); </script> block.
  • Every page should have a userContext instance to check user is logged-in or Anonymous one. Based on this, the page will redirect to login page for authentication.
  • Site-wide settings should be loaded and passed into the controls at the page level. This eliminates the dependency to the config file at the time the files are being loaded. Dependant objects will be passed into the control when an instance is created.
    exampleExample

     

    Code Block
    languagejs
    var options = {}

    
    options.domElement = $('#BillingShippingAddress')[0];

    
    options.templatePath = eb_Config.SitePath + "html/BillingShippingAddress.html";

    
    eb_Config.config(options, eb_billingShippingAddress);
    
    
    options.shoppingCart = eb_shoppingCart.live;

    
    options.userContext = eb_UserContext.live;

     

  • Control models should be instantiated at the page level inside of a document. ready jQuery object.
    example Example :

    //Payment Summary Form.
     

    Code Block
    languagejs
    var paymentSummaryDetails = {}

    
    paymentSummaryDetails.domElement = $('#paymentSummary')[0];

    
    paymentSummaryDetails.templatePath = eb_Config.SitePath + "html/PaymentSummary.html";

    
    paymentSummaryDetails.shoppingCart = eb_shoppingCart.live;

    
    paymentSummaryDetails.data = undefined;
    
    
    eb_Config.config(paymentSummaryDetails, eb_paymentSummaryDetails);

    
    eb_paymentSummaryDetails.render(paymentSummaryDetails).done(function () {

    
    	eb_paymentSummaryDetails.live = new eb_paymentSummaryDetails.model(paymentSummaryDetails); //Page's live instance of the model. Handy for troubleshooting.

    
    	eb_paymentSummaryDetails.live.hidePaymentDetails(0);

    
    	ko.applyBindings(eb_paymentSummaryDetails.live, eb_paymentSummaryDetails.live.domElement);//Apply KO bindings, fire up the control

    
    }).fail(function (data, msg, jhr) {

    
    	console.error('Failed to render payment Summary Details..' + data);

    
    });

     


  • Instances of the control's model should be added to that controls collection for reference. ex. ebLogin.live
  • Once instance created then Apply KO bindings and fire up the control.

    example: ko.

    Example: 
     

    Code Block
    languagejs
    ko.applyBindings(eb_paymentSummaryDetails.live, eb_paymentSummaryDetails.live.domElement);//Apply KO bindings, fire up the control

Sitewide guidelines with examples.

  • ebConfig.js file available under root/js/configuration folder.
  • Sitewide settings should live in the sitewide configuration file.

    example

    Example

    Code Block
    languagejs
    //Sitewide default site path value.

    
    eb_Config.SitePath = "http://localhost:63818/";
    
    
    //Service path

    
    eb_Config.ServicePath = 'http://localhost:51809/';
    
    
    //Login Page URL

    
    eb_Config.loginPageURL = eb_Config.SitePath + "login.html";
    
    
    //Thumbnail image folder path

    
    eb_Config.thumbnailImageURL = eb_Config.SitePath + 'images/thumbnail/';
    
    
    //Large image folder path

    
    eb_Config.largeImageURL = eb_Config.SitePath + 'images/large/';
    
    
    //Image path extension

    
    eb_Config.imageExtension = '.jpg';
    
    
    //This property will load default image [No Photo Available Image] instead original one for product.

    
    eb_Config.loadDefaultImage = true;
    
    
    eb_Config.defaultDateFormat = "MM/DD/YYYY"; // Default date format
    
    
    eb_Config.eventsDateFormat = "MM/DD/YYYY hh:mm A"; // Event date format
    
    
    eb_Config.roundOffDigitsAfterDecimal = 2;  //Digit after decimal
     
  • Pass site level configuration to a control on page startup. SitePath and Service Path will be passed in by default if not explicitly specified in options.
    example : eb eb_Config.config(options, eb_billingShippingAddress);

  • Sitewise get URL parameter function to get URL attributes value.
    example:  eb  eb_Config.getUrlParameter("RedirectPage")

How to add wait indicator on control.

  • Need to add below HTML div in template file, loaderwrapper class css added in eb6.css

    <div class="loaderwrapper" data-bind="visible: showLoader">
    <div class="ebloader"></div>
    </div>

  • Create an observable property _that.showLoader = ko.observable(0); in control model.
  •  Add _that.showLoader(1); for show loader
  •  Add _that.showLoader(0); for stop loader


Info

Currently in 6.0 we have static drop down for Prefix, Suffix email type, gender fields on membership application and profile control.

 

Following Control List have been built in e-Business 6.0 Beta Release:

  • Login
  • SignUp
  • Product Catalog
  • Product Details
  • View Cart
  • Payment Summary
  • Billing Same as Shipping
  • Review Order
  • Checkout
  • Order Confirmation
  • Person Profile
  • Order History
  • Topic of Interest
  • Order History Filter Sort
  • Saved Payment Method
  • Payment Method
  • Password Reset
  • Password Reset Request
  • Event Catalog
  • Event Detail
  • Event Registration
  • Event Calendar
  • Event Summary
  • Membership Application
  • Donation
  • Make My Payment