People who have used JavaScript frameworks such as ANGULARJS, backbone, or ember are familiar with how MVC works in the UI (user interface, front-end). These frameworks implement MVC, which makes it easier to implement changes to views as needed in a single page, while the core concept of model-view-Controller (MVC) is the controller that handles incoming requests, a view that displays information, a model that represents business rules, and data access.
Therefore, when you need to create an application that needs to switch between different content in a single page, we usually choose to use one of these frameworks. However, if we just need a framework to implement view switching in one URL without the need for additional bundled functionality, we don't have to use complex frameworks like angular and ember. This article tries to use simple and effective methods to solve the same problem.
Concept
The code in the application uses the "#" in the URL to implement the navigation of the MVC pattern. The application starts with a default URL, loads the application view with code based on the hash value, and applies the object-model to the view template.
The URL format looks like this:
Http://Domain Name/index.html#/route Name
The view content must bind the values and properties of the object model in the manner of {{Property-name}}}. The code looks for this specialized template format and replaces the property values in the object model.
Views that are loaded asynchronously in an Ajax manner are placed in a placeholder for the page. A view placeholder can be any element (ideally, div), but it must have a special attribute that the code locates based on this particular attribute, which also helps with the implementation of the Code. When the URL changes, the scene is repeated, and another view is loaded. It sounds simple! The following flowchart explains the message jumps in this particular implementation.
Write code
We started with a basic modular design pattern and eventually exposed our libs to the global scope in the form of façade design patterns.
; (Function (w, d, undefined) {//rest of the Code}) (window, document);
We need to store the view elements in a variable so that we can use them more than once.
var _viewelement = null; element that'll be used to render the view
We need a default path. There is no routing information in the URL, so the default view can be loaded instead of displaying a blank page.
var _defaultroute = null;
Now we're going to create the construction method for our main MVC object. We will store the routing information in "_routemap"
var jsmvc = function () {
Mapping object for the routes
This._routemap = {};
}
It's time to create the routing object, and we'll store the routing, template, and controller information in this object.
var routeobj = function (c, r, T) {
This.controller = C;
This.route = R;
This.template = t;
}
Each URL will have a dedicated routing object routeobj. All of these objects will be added to the _routemap object, so that we can get them in Key-value way later.
In order to add routing information to the MVC Libs, we need to expose a method in the Libs. So let's create a method that can be used by each controller to add a new route.
JsMvc.prototype.AddRoute = function (Controller, route, template) {
This._routemap[route] = new Routeobj (Controller, route, template);
}
Method Addroute receives 3 parameters: Controller, Routing and template (Contoller, route and template). They were:
Controller: The role of the controller is to access specific routes.
Route: Route of route. This is the part behind the # in the URL.
Template: This is an external HTML file that is loaded as a view of this route. Now our libs need a pointcut to parse the URL and provide services for the associated HTML template page. In order to accomplish this, we need a method.
The Initialize method does the following things:
1 Gets the initialization of the element associated with the view. The code requires an element with the View property, which can be used to find in an HTML page:
2 Set the default route
3 Verify that the view element is reasonable
4 Binding window Hash Change event, the view can be updated in time when the URL is changed with different hash values
5) Finally, start MVC
Initialize the MVC Manager object to start functioning
JsMvc.prototype.Initialize = function () {
var startmvcdelegate = Startmvc.bind (this);
Get the HTML element that'll be used to render the view
_viewelement = D.queryselector ('[ view]');
if (!_viewelement) return; Do no if view element is not found
Set the default route
_defaultroute = This._routemap[object.getownpropertynames (This._routemap) [0]];
Start the MVC Manager
W.onhashchange = startmvcdelegate;
Startmvcdelegate ();
}
In the code above, we created an agent method Startmvcdelegate from the Startmvc method. When the hash value changes, the proxy is invoked. Here's what we do when the hash value changes:
1) Get hash value
2 Get the route value from the hash
3 Gets the routing object from the routing map object _routemap routeobj
4 If there is no routing information in the URL, you need to get the default routing object
5 Finally, call the controller associated with this route and provide a service for the view element's views
All of the above steps are implemented by the following Startmvc method
function to start the MVC support
function Startmvc () {
var Pagehash = W.location.hash.replace ('#', ''),
Routename = NULL,
Routeobj = null;
Routename = Pagehash.replace ('/', '');//get the name of the route from the hash
Routeobj = This._routemap[routename]; Get the Route object
Set to default route object if no route found
if (!routeobj)
Routeobj = _defaultroute;
LoadTemplate (Routeobj, _viewelement, Pagehash); Fetch and set the view of the route
}
Next, we need to load the appropriate view asynchronously using an XML HTTP request. To do this, we pass the value of the routed object and the view element to the method loadtemplate.
Function to load external HTML data
function LoadTemplate (routeobject, view) {
var xmlhttp;
if (window. XMLHttpRequest) {
Code for ie7+, Firefox, Chrome, Opera, Safari
XMLHTTP = new XMLHttpRequest ();
}
else {
Code for IE6, IE5
XMLHTTP = new ActiveXObject (' microsoft.xmlhttp');
}
Xmlhttp.onreadystatechange = function () {
if (xmlhttp.readystate = = 4 && xmlhttp.status = 200) {
Loadview (Routeobject, view, Xmlhttp.responsetext);
}
}
Xmlhttp.open (' Get', routeobject.template, true);
Xmlhttp.send ();
}
Only the load view is currently left and the object model is bound to the view template. We will create an empty model object and then pass the model associated with the method to wake the routing controller. The updated model object is bound to the HTML template in the XHR call that was previously loaded.
The Loadview method is used to invoke the Controller method and to prepare the model object.
The Replacetoken method is used to bind the model along with the HTML template
Function to load the view with the template
function Loadview (Routeobject, viewelement, viewhtml) {
var model = {};
Get the resultant model from the controller to the current route
Routeobject.controller (model);
Bind the model with the view
viewhtml = Replacetoken (viewhtml, model);
Load the view into the view element
viewelement.innerhtml = viewhtml;
}
function Replacetoken (viewhtml, model) {
var modelprops = object.getownpropertynames (model),
Modelprops.foreach (function (element, index, array) {
viewhtml = Viewhtml.replace ('{ {' + element + '}} &apos, model[element]);
});
return viewhtml;
}
Finally, we will expose the plugin to JS global scope outside
Attach the MVC object to the window
W['jsmvc&apos] = new Jsmvc ();
Now it's time to use this MVC plugin in our single-page application. In the next code snippet, the following are implemented:
1 introducing this code into the Web page
2 with the controller to add routing information and view template information
3) Create Controller function
4 Finally, initialize LIB.
In addition to the links above we need to navigate to different paths, a container element's View property contains the view template HTML.
<! DOCTYPE html>
<title>javascript mvc</title>
<script src= "Jsmvc.js" ></script>
<!--[if Lt IE 9]> <script src= "Jsmvc-ie8.js" ></script> <! [endif]-->
<style type= "Text/css" >
. Navlinkcontainer {
padding:5px;
Background-color:lightyellow;
}
. NavLink {
Background-color:black;
Color:white;
font-weight:800;
Text-decoration:none;
padding:5px;
border-radius:4px;
}
. Navlink:hover {
Background-color:gray;
}
</style>
<body>
<div class= "Navlinkcontainer" >
<a class= "NavLink" href= "Index.html#/home" >Home</a>
<a class= "NavLink" href= "Index.html#/contact" >Contact</a>
<a class= "NavLink" href= "Index.html#/admin" >Admin</a>
</div>
<br/>
<br/>
<div view></div>
<script>
Jsmvc.addroute (HomeController, 'home', ' views/home.html');
Jsmvc.addroute (Contactcontroller, 'contact', ' views/contact.html');
Jsmvc.addroute (Admincontroller, 'admin', ' views/admin.html');
Jsmvc.initialize ();
function HomeController (model) {
Model. message = ' Hello world';
}
function Contactcontroller (model) {
Model. FirstName = "John";
Model. LastName = "Doe";
Model. Phone = '555-123456';
}
function Admincontroller (model) {
Model. UserName = "John";
Model. Password = "MyPassword";
}
</script>
</body>
The above code has a paragraph that contains a conditional annotation for IE.
<!--[if Lt IE 9]> <script src= "Jsmvc-ie8.js" ></script> <! [endif]-->
If the version of IE is below 9, then the Function.bind,object.getownpropertynames and Array.foreach properties will not be supported. So we're going to feed the code back by determining whether the browser is below IE9.
The contents of which are home.html, contact.html and admin.html please look below:
Home.html:
{{Message}}
Contact.html:
{{FirstName}}} {{LastName}}}
<br/>
{{Phone}}}
Admin.html:
<div style= "Padding:2px;margin:2px;text-align:left;" >
<label for= "txtUserName" >user name</label>
<input type= "text" id= "txtUserName" value= "{{UserName}}"/>
</div>
<div style= "Padding:2px;margin:2px;text-align:left;" >
<label for= "Txtpassword" >Password</label>
<input type= "Password" id= "Txtpassword" value= "{password}}"/>
</div>
The complete code can be obtained from the given download link.
How to run the code
Running the code is simpler, and you need to create a Web application on your favorite Web server, as an example of IIS.
First, add a Web application to the default site.
Then set the required information: alias, physical path, application pool, user authentication information, click OK.
Finally navigate to the content directory of the Web application and browse the HTML page you want to open.
Running on the server is necessary because the code loads from the view stored in the external file, the browser will not allow our code to execute in a non-hosted server environment. Of course, if you use Visual Studio to right-click on the target HTML file, select ' View in Browser '.
Browser support
This code is supported by most modern browsers. For IE8 and the following browsers, there is a separate code to support, but unfortunately, this code is far more than 100 lines. So this code is not hundred-browser compatible, so you need to fine-tune your code when you decide to use it in your project.
Points of interest
This example demonstrates shows us that it is really unnecessary to use JS libraries and frameworks for very specific requirements. Web applications are resource-intensive, and it's best to use the necessary code to get rid of other redundant parts.