May 21, 2017

Single-page sites or Single Page Applications (SPA) are cool. Their main advantage is that SPA is faster and more responsive to user actions. This is achieved by transferring the operating logic to client side and active interaction with the server via ajax.

There is an opinion that SPAs are powerful applications in Angular or React, moving tons of data in some control panel or in a complex service. And in general this is true. But I am convinced that it makes sense to write single-page applications not only for such services, but also for ordinary corporate business card sites.

Why is this necessary and how to do it with a little effort? More on this below. Let's go.

So, why this pampering?

The most important thing is the speed of work.

Of course, when developing a one-page business card website, we will encounter some problems:

  • 1. How to approach, where to start?
  • 2. How to deal with browser history, with the History API?
  • 3. Which framework or library should I study: Angular, React? And we don't know a single one...
  • 4. How to force search engines to index a one-page site?

Answers to these questions:

  • 1. Let’s look at it in the same article, using the example of a simple website
  • 2. I’ll also tell you below, this is a dozen lines of code
  • 3. None, we’ll make do with native javascript and jQuery as an assistant
  • 4. The next article in this series will be about search engines.

Why without angular-react?
Of course, these are very necessary topics, I recommend studying them. But for our example they will not be needed; we only need to have minimal knowledge of javascript.

One-pagers are the topic of more than one article. This will be a whole project, a series of articles of at least three pieces. And it will cover a variety of topics. But let me clarify. We will build a simple admin panel with interaction with the server via REST API (at least at the very beginning). In the first lessons, our one-page website will be an ordinary business card of a dozen pages. But the site will work without reloading pages and will delight our users with the speed and responsiveness of the interface.

The idea of ​​the site, how it works

Let's take the most common corporate website: home page, section "About the project", contacts and blog. The Blog section will have several links to internal pages. On each page we will add some content and insert some cross-references.

Each page on a site typically has repeating content. For us this will be a header and a menu. And there is the main content of the page that changes. We will do this: we will load the page just once, and then by clicking on the links, we will dynamically load the necessary content using Ajax. At the same time, we will change the page title in the browser tab, the url in the address bar and remember the history in the browser so that navigation through the browser's Back/Forward buttons works.

Content for each individual page will be stored in a separate html file.

You can immediately see what we end up with -

Site structure and preparatory work

The file-folder structure is as follows. In the root of the project there is a file index.php and .htaccess. I’ll tell you why exactly php and not html later. The css folder contains styles in the main.css file. The js folder contains the jquery.js library and the main application file main.js. The pages folder contains html files with the contents of the site - one file for each page.

Preparing content

I will make a demo site using my webdevkin project as an example. The set of pages will be like this:

  • — main - Home
  • — about - About the project
  • — blog - Blog
    • — shop - Online stores
    • — frontend - Frontend
    • — mysql - MySql Database
    • — widgets - Embeddable widgets
  • — simple - Project Simple
  • — contacts - Contacts

Accordingly, the pages folder will contain 9 html files. You can find all the markup for the content in . As an example, I will give the contents of only one file - simple.html

The Simple project grew out of a blog site. The idea of ​​the project is to make simple and easily embedded widgets that help interact with visitors to your site. Right now there is already a survey widget that is easy to create and embed on any website.

As you can see, there is no head, body, html, script here - only markup related to a specific page.

index.php and .htaccess

Why not index.html?
The fact is that on our site there will be one single physical page - index. But we are also interested in such addresses as site.ru/about, site.ru/contacts, etc. But there are no about and contacts pages at the root of our site. The pages folder with a set of html files is not a full-fledged page, but simply pieces of html code that are built into the overall framework.

Therefore, so that when accessing site.ru/about we don’t get 500, 403 and God knows what other errors, we must redirect all incoming requests to the site to index.php, which will resolve these requests. However, for now our index.php is ordinary html markup without a single line of php code (but this is only for now). And in .htaccess we will write the following. You will rarely have to return to it.

RewriteEngine On Options +SymLinksIfOwnerMatch RewriteCond %(REQUEST_FILENAME) !-d RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-l RewriteRule ^(.+)$ index.php?q=$1

On topic
I once wrote an article about a Simple RESTful service in native PHP. There you will find a little more information about this method of redirecting requests.

Our html code will be very simple. Css/main.css styles are included in head. There are 2 js files in the footer: js/jquery.js and js/main.js. And in body there will be the following:

First we display the menu. Next comes the page title. And below is an empty div with id=content (don’t pay attention to style="" - the parser will someday piss me off and I’ll replace it). #content will dynamically load page content from pages/*.html files. Nothing interesting yet.

Just pay attention to the data-menu and data-link="ajax" attributes of the links. They are introduced to distinguish navigation links from regular ones. external links, which will also be on our website. data-link="ajax" means that when you click on this link, we will intercept the standard behavior of the browser and take the work with the link into our own hands. And data-menu means which main menu item will be highlighted when you click on this link. Here the data-menu is duplicated with the href attribute, but other options are possible. For example, when we go to the frontend section of the blog, we will indicate data-menu="blog".

2 examples for clarity:

simple.ru Home page simple.ru Styles main.css

Let’s quickly scroll through and copy-paste the most boring part - the css/main.css file.

Body ( position: relative; font-family: "Helvetica Neue Light", "Helvetica Neue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; font-size: 1em; font-weight: 400; color: #333; ) a, a:visited ( color: steelblue; ) a:hover ( color: navy; ) .wrapper ( width: 80%; margin: 0 10%; ) .spa-title ( font-size: 1.2em; text- align: center; ) menu ( margin-top: 2em; padding: 0; text-align: center; ) menu a ( display: inline-block; margin-right: 10px; padding: 5px 15px; text-decoration: none; ) menu a:hover, menu a.active ( background-color: steelblue; color: white; ) .page-title ( text-align: center; ) ul li ( list-style-type: circle; )

And now the most interesting thing is the javascript code that will turn our set separate files into a one-page site.

javascript General code and configs

Let's set the js code framework.

Var app = (function() ( var config = (); var ui = (); // Event binding function _bindHandlers() ( // ... ) // Application initialization function init() ( // ... _bindHandlers (); ) // Return outside return ( init: init ) ))(); // Launch the application $(document).ready(app.init);

We have a separate app module, which runs its init function when the page loads. We attach event handlers in it and execute some more code. We also see 2 objects: config and ui. All dom elements that we will need in our work will be cached in the ui.

Var ui = ( $body: $("body"), $menu: $("#menu"), $pageTitle: $("#page-title"), $content: $("#content") );

We need $menu to highlight individual menu items, $pageTitle will be changed dynamically when moving between pages, and $content will be loaded with the contents of the pages/*.html files

But config looks more interesting.

Var config = ( siteTitle: "Webdevkin SPA", mainPage: "main", pages: ( main: ( title: "Main", menu: "main" ), about: ( title: "About the project", menu: "about " ), blog: ( title: "Webdevkin-a Blog", menu: "blog"), simple: ( title: "Simpple Project", menu: "simpple" ), contacts: ( title: "Contacts", menu: "contacts" ), shop: ( title: "Online stores", menu: "blog"), frontend: ( title: "Articles about the frontend", menu: "blog"), mysql: ( title: "Database Mysql data", menu: "blog" ), widgets: ( title: "Embeddable javascipt widgets", menu: "blog" ) ) );

siteTitle: "Webdevkin SPA" - site title, used in several places.
mainPage: "main" - specify home page site, the one that opens when you go to site.ru. Now this is the main page, but it might easily occur to you to put the start page, for example, “About the project” - about.

The most important thing in the entire config is the pages object. Each object field describes one page of the site. Now we only need 2 items: the page title and the menu to which this page belongs. The object keys, that is, the pages, match the file names in pages/*.html and the href attributes in internal links.

And finally, we’ll write the code for which we started everything. You may be surprised, but the code that directly performs the work of maintaining the site is much less than the preparation for writing it.

Loading content using ajax. History API

Let's go in order. Let's work on the init function, which contains the binding of the necessary events _bindHandlers

// Event binding function _bindHandlers() ( ui.$body.on("click", "a", _navigate); window.onpopstate = _popState; )

In the first line, we catch clicks on internal links a and send them to the _navigate function. Now we are finally convinced that separate attributes data-link="ajax" are needed :-)

Next window.onpopstate = _popState;
From the documentation.
The popstate event is dispatched to the window object whenever the active history entry changes between two history entries for the same document.
Simply put, this is the operation of the Back/Forward buttons in the browser. As we can see, the native behavior of the browser also needs to be intercepted. Therefore, we will give control to the _popState function.

For a better understanding, I will provide the code for both functions at once

// Click on the link function _navigate(e) ( e.stopPropagation(); e.preventDefault(); var page = $(e.target).attr("href"); _loadPage(page); history.pushState(( page: page), "", page); ) // Back/Forward buttons function _popState(e) ( var page = (e.state && e.state.page) || config.mainPage; _loadPage(page); )

When an explicit click on the _navigate link occurs, we stop the click event from bubbling and cancel the default behavior of the browser (following the link). Then we identify the page we want to load (understood by the href attribute) and call new feature _loadPage. She will do all the main work of loading content, changing the title, and so on. And at the end, through history.pushState we add new entry in the browser history. Yes, we ourselves explicitly create the browser history. Then, when we consider it necessary. And we save the data about the loaded page into an object (page: page). This data will be useful to us in the next _popState function.

In _popState the idea is similar: we are looking for desired page and run the same _loadPage.

Var page = (e.state && e.state.page) || config.mainPage;

e.state && e.state.page - pulls out a page for us from the history object, which we prudently recorded in _navigate. If the e.state object is not available (for example, when we first visited the site.ru site and have not yet had time to wander around it), then we take the page specified as the main page in our config - config.mainPage.
In all fairness, the history.pushState function and the fact that an e.state object with data written to pushState is available in window.onpopstate is all we need to know about the History API. For more curious comrades, I have no doubt that googling will help you find others good ways working with browser history.

We will not engage in deep research, but will write the code for the main function _loadPage

// Load content by page function _loadPage(page) ( var url = "pages/" + page + ".html", pageTitle = config.pages.title, menu = config.pages.menu; $.get(url, function (html) ( document.title = pageTitle + " | " + config.siteTitle; ui.$menu.find("a").removeClass("active"); ui.$menu.find("a").addClass ("active"); ui.$pageTitle.html(pageTitle); ui.$content.html(html));

He looks quite ordinary. First, we form the url, that is, the path where we will download the html for the page. Then we pull out the page title and the menu item to be selected from the config. Next, we get the html content of the page through the banal jQuery.get and perform a number of simple actions.

a) Update the page title
b) In 2 lines, select the desired menu item
c) Change the title on the page itself, in the html code
d) Load the actual html content of the page obtained from the url

Almost everything! There is a small moment left. If we now go, for example, to the site.ru/blog page and update it, then it will not be the blog that will load, but an empty page. Because during initialization we do not call _loadPage. To fix this, we need to add a couple of lines to the init function, which will ultimately look like this

// Initialize the application function init() ( var page = document.location.pathname.substr(1) || config.mainPage; _loadPage(page); _bindHandlers(); )

That's all for sure now!

Let's summarize and recall the links

So, we wrote a simple but fully functional one-page website, and also learned a little about how the History API works. Honestly, I feel like the director of a bad movie where 80% of the time leads to some kind of grandiose outcome, and in the end everything turns out to be much easier than expected.

On the one hand, almost all the code is just preparation, wiring, writing configs and other boring things. But really useful code, which does the actual work, takes up 2 dozen lines.

But on the other hand, the configs allowed us to create a structure that is easily expandable when adding new pages. Plus, in the next article we will see the importance of this rather large config when we teach search engines to index our one-page website. Well, styles are needed to just make it look prettier :-)

There is also a third party. For those not familiar with one-page sites, this is not a simple thing at all. And I think it’s great when an initially seemingly complex topic, upon detailed consideration, turns out to be completely solvable, and without great effort on our part.

Next, our demo site will gradually develop. In the next article, we will begin to prepare the site for indexing by search engines, because it is known that single-page websites are indexed very poorly if special actions are not taken. But this is from the next articles in the series.

And a small survey

This article will focus on Single Page Application (SPA). The pros and cons of a web application built on the principles of a single page site (SPA) will be considered.

What is SPA

Single Page Application - abbreviated SPA, translated into Russian means “Single Page Application”. In other words, SPA is a web application hosted on one web page, which, to ensure operation, loads all the necessary code along with loading the page itself. This type of application appeared relatively recently, with the beginning of the HTML5 era and SPA is a typical representative of HTML5 applications.

As we know, HTML5 is nothing more than HTML + CSS3 + JavaScript + [few new tags]. Thus, SPAs are applications written in JavaScript. And, therefore, slightly paraphrasing the previous definition we get:

“SPA is a web application hosted on one page, which, to ensure operation, loads all javascript files (modules, widgets, controls, etc.), as well as CSS files, along with loading the page itself.”

If the application is quite complex and contains rich functionality, such as an electronic document management system, then the number of files with scripts can reach several hundred, or even thousands. And “...loading all scripts...” in no way means that when loading the site, all hundreds and thousands of files with scripts will be downloaded at once. To solve the problem of loading a large number of scripts into SPA, an API called AMD is called upon. AMD implements the ability to download scripts on demand. That is, if the “main page” of a one-page portal required 3 scripts, they will be loaded immediately before the program starts. And if the user clicked on another page of a one-page portal, for example, “About the program,” then the AMD principle will load the module (script + markup) only before going to this page.

It turns out a little crumpled: “One page... another page, third page... one-page portal.” Let’s dot all the “E”s. We will call the page of the site on which all links to all CSS and links to scripts necessary for the SPA to work “Web page”. The file with such a page is usually called “index.html” (in ASP.NET MVC it ​​can be index.cshtml or index.vbhtml or even index.aspx) And the pages that the user switches inside a one-page portal will be called “modules”.

Let's look at the pros and cons of this approach. Why is all this needed and why is SPA so popular?

SPA: Pros

The first advantage worth noting is the fact that SPA applications work perfectly on both desktop and mobile devices. “Large” computers, tablets, smartphones, and, ultimately, simple phones(some) can work seamlessly with sites built on the SPA principle. So, the first “plus” is that it works on a large number of devices, which means that by creating one application, you get a much larger audience of users than when using the standard approach.

Next, the second “plus” is a rich user interface, the so-called User Experience. Since there is only one web page, it is much easier to build a rich, rich user interface. It's easier to store session information, manage view states, and control animation (in some cases).

The third “plus” is that SPA significantly (by several times) reduces the so-called “circling”, that is, downloading the same content over and over again. If your portal (site) uses a template, then along with the main content of any page, the site visitor must download the template markup. Yes, data caching at this stage of WWW development has achieved the highest results, but if there is nothing to cache, then neither time nor resources are wasted on it.

SPA: Cons

If you program in C#, then the only disadvantage of SPA is the need to learn JavaScript. In any case, I was unable to find out any other global problems.

Components of SPA

The principles of any framework (we'll talk about them later) that implements the SPA paradigm must adhere to the following concepts and definitions:

  • SPA supports client navigation. All of the user’s “walks” through page modules are uniquely recorded in the navigation history, and the navigation is “deep”, that is, if the user copies and opens a link to an internal page module in another browser or window, he will be taken to the corresponding page.
  • SPA is located on one web page, which means that everything necessary for the operation of the site (portal), scripts and styles, must be defined in one place in the project - on a single web page.
  • SPA permanently stores the state (important variables) of the client (client script) in the browser cache or in Web Storage.
  • SPA loads all the scripts required to start the application when the web page is initialized.
  • SPA gradually loads modules on demand.
SPA templates

As you probably already guessed, SPA is an abstract concept. This is the principle of application architecture. Let's talk about where to start when developing a website according to SPA principles.

There are a large number of basic libraries (framework - from the English word framework - “base, structure, framework”) that implement the Single Page Application principle. What do these frameworks provide:

  • provide basic principles for SPA development, minimizing labor costs for solving universal problems (see section “Components of SPA);
  • frameworks were created by a community of developers, which means they use the experience of creating websites of many programmers;
  • frameworks are the starting point for creating a structure based on a Single Page Application.

Since I have been working on the NET platform for many years, I will be looking at Single Page Application templates based on ASP.NET. Let's look at the following comparison table.

Comparison of SPA template features

The table shows the most common templates for the basis of building a Single Page Application application. Please note that the basic building blocks for building a full-fledged framework, such as DurandalJS and HotTowel, which are highlighted in green, are highlighted in blue.

So, following the data provided in the table, you can create a Single Page Application application using bare ASP.NET and KnockoutJS. However, you will have to write the implementation of working with data (DAL) yourself, as well as managing navigation and navigation history as well.

Single Page Applications

This and subsequent articles will describe the Web API tool, which is a relatively new addition to the ASP.NET platform that allows you to quickly and easily create web services that expose an API to HTTP clients.

The Web API tool is based on the same foundation as ASP.NET MVC Framework applications, but is not part of the ASP.NET MVC Framework. Instead, Microsoft took a set of key classes and associated characteristics from the System.Web.Mvc namespace and duplicated it in the namespace System.Web.Http.

The idea is that the Web API is part of the main ASP.NET framework and can be used in other types of web applications or as a standalone web services engine. One of the main applications Web tools The API is considered to create single-page applications (SPA) by combining the Web API with the capabilities of the ASP.NET MVC Framework. Next we will show you what SPA applications are and how they work.

Simplifying the creation of web services is an integral feature of the Web API. It represents a significant improvement over other web service technologies that Microsoft has offered over the past decade. I love the Web API tool and you should use it in your projects, not least because it's simple and builds on the same design solution, as ASP.NET MVC Framework.

The term single page application (SPA) is used quite widely. The most consistent definition is that it is a web application whose initial content is delivered as a combination of HTML markup and JavaScript code, and subsequent operations are performed using a REST web service that delivers the data to JSON format in response to Ajax requests.

This is different from the kind of applications that were built in the previous examples, where the results of user operations were new HTML documents generated in response to synchronous HTTP requests. Such applications will be called round-trip applications (RTA).

The benefits of the SPA application are that it requires less bandwidth and the user gets a smoother interface. Disadvantages include that this smoother interface may be difficult to achieve, and the complexity of the JavaScript code required for an SPA application means careful design and testing is required.

Most applications mix SPA and RTA techniques, with each major area of ​​application functionality delivered as an SPA, and navigation between areas of functionality managed using standard HTTP requests that create a new HTML document.

Single Page Application Example

For the purposes of these articles in Visual Studio Created a new MVC project named WebServices using the Empty template. In the Add folders and core references for section, the MVC and Web API checkboxes have been checked as shown in the image below:

This project will be used to create a regular ASP.NET MVC Framework application, then with using the Web API will create a web service. Once the web service is ready, the ASP.NET MVC Framework application will be turned into a single page application.

Creating a model

The application will create and maintain a set of requests for room reservations. The application is planned to be kept simple so that one can focus on the mechanics of the facility being described, so booking requests will consist of only the customer's name and location of the premises. A class file named Reservation.cs has been added to the Models folder, the contents of which are shown in the example below:

Namespace WebServices.Models ( public class Reservation ( public int ReservationId ( get; set; ) public string ClientName ( get; set; ) public string Location ( get; set; ) ) )

The plan is to create a simple in-memory collection of Reservation objects that will act as a data store. There is no need to install a database, but you do need to be able to perform CRUD operations on a collection of model objects to demonstrate some important aspects of the Web API. A class file called ReservationRepository.cs is also added to the Models folder:

Using System.Collections.Generic; using System.Linq; namespace WebServices.Models ( public class ReservationRepository ( private static ReservationRepository repo = new ReservationRepository(); public static ReservationRepository Current ( get ( return repo; ) ) private List data = new List ( new Reservation ( ReservationId = 1, ClientName = "Peter" , Location = "Hotel"), new Reservation (ReservationId = 2, ClientName = "Vasya", Location = "Library"), new Reservation (ReservationId = 3, ClientName = "Igor", Location = "Dining Room"), ); public IEnumerable GetAll() ( return data; ) public Reservation Get(int id) ( return data.Where(r => r.ReservationId == id).FirstOrDefault(); ) public Reservation Add(Reservation item) ( item.ReservationId = data.Count + 1; data.Add(item); return item; ) public void Remove(int id) ( Reservation item = Get(id); if (item != null) ( data.Remove(item); ) ) public bool Update(Reservation item) ( Reservation storedItem = Get(item.ReservationId); if (storedItem != null) ( storedItem.ClientName = item.ClientName; storedItem.Location = item.Location; return true; ) else ( return false; ) ) ) )

In a real project, we would have to take care of breaking the tight coupling between classes and introducing interfaces into the application, as well as providing dependency injection. However, this topic only focuses on Web APIs and SPA applications, so when it comes to standard practices, some simplifications will be made.

The storage class has an initial list of three Reservation objects and defines methods that let you view, add, delete, and update the collection. Because there is no persistence in the store, any changes made to the store are lost when the application is stopped and restarted, but this example is entirely focused on the way the content can be delivered rather than how it is stored on the server. To provide a certain amount of persistence between requests, an instance of the ReservationRepository class is created, which is accessible through the static property Current.

Installing NuGet packages

This and subsequent articles will use three NuGet packages: jQuery, Bootstrap, and Knockout. jQuery Libraries and Bootstrap have already been described and used previously. Knockout is a library that Microsoft has adapted for single page applications. It was created by Steve Sanderson. Although Steve works for Microsoft, the Knockout package is available as open source on the Knockout library website and has been widely adopted. We'll show you how Knockout works later, but for now you need to install the packages mentioned above.

Select Tools --> Library Package Manager --> Package Manager Console to open the window command line NuGet and enter the following commands:

Install-Package jquery -version 1.10.2 -projectname WebServices Install-Package bootstrap -version 3.0.0 -projectname WebServices Install-Package knockoutjs -version 3.0.0 -projectname WebServices

Adding a Controller

A controller named Home is added to the example project, the definition of which can be seen in the example:

Using WebServices.Models; using System.Web.Mvc; namespace WebServices.Controllers ( public class HomeController: Controller ( ReservationRepository repository = ReservationRepository.Current; public ViewResult Index() ( return View(repository.GetAll()); ) public ActionResult Add(Reservation item) ( if (ModelState.IsValid) ( repository.Add(item); return RedirectToAction("Index"); else return View("Index"); public ActionResult Update(Reservation item) ( if (ModelState.IsValid && repository.Update(item)) return RedirectToAction( "Index"); else return View("Index");

This is a completely typical controller for this simple application. Each action method corresponds directly to one of the methods in the store. The controller's only usefulness comes from performing model validation, selecting views, and performing redirection. Of course, in a real project there would be additional domain logic, but since the example application is so basic, the controller ends up being little more than a simple wrapper around the store.

Adding Layout and Views

To generate content for the application, a Views/Shared folder is created and a view file named _Layout.cshtml is added with the content shown in the example below:

@ViewBag.Title @RenderSection("Scripts") @RenderSection("Body")

This basic layout provides elements for the Bootstrap library CSS files. The layout defines two sections, Scripts and Body, which will be used to insert content within the layout. The next step is to create a top-level view for the application. Although you will be building a regular ASP.NET MVC Framework application next, you know that you will eventually build a single page application.

It will be easier to do the transformation if you create a single view that contains all the HTML markup required for the application, even if the result initially looks a little strange. A view file named Index.cshtml is added to the Views/Home folder, the contents of which are shown in the example below:

@using WebServices.Models @model IEnumerable @( ViewBag.Title = "Reservations"; } @section Scripts { } @section Body { @Html.Partial("Summary", Model) @Html.Partial("Editor", new Reservation()) }!}

The view model for this view is an enumeration of Reservation objects, and two partial views are created to provide the building blocks of functionality that the user will see. The file with the first partial view is called Summary.cshtml. This file is created in the Views/Home folder:

@model IEnumerable All orders

IDNameRoom@foreach (var item in Model) ( }
@item.ReservationId @item.ClientName @item.Location @Html.ActionLink("Delete", "Remove", new ( id = item.ReservationId), new ( @class = "btn btn-xs btn-primary" ))

The view model for the partial view is the same enumeration of Reservation objects and it is used to generate a styled table using Bootstrap as an element

, which displays the property values ​​of these objects. The Html.ActionLink() helper method is used to generate a link that will call the Home controller's Remove action; the link is styled as a button using Bootstrap.

Another partial view is called Editor.cshtml and is also located in the Views/Home folder. The contents of this file are shown in the example below. The partial view contains a form that is used to create new booking requests. Submitting the form causes the Home controller's Add action to be called.

@model WebServices.Models.Reservation Create order @using (Html.BeginForm("Add", "Home")) ( Client Name @Html.TextBoxFor(m => m.ClientName, new ( @class = "form-control" )) Placement @Html.TextBoxFor(m => m.Location, new ( @class = "form-control" )) Save )

Setting the start URL and testing the application

The last preparatory step involves setting the location where Visual Studio will go when the application starts. Select WebServices Properties from the Project menu in Visual Studio, in the dialog box that opens, go to the Web tab, and select the Specific Page radio button in the Start Action category. There is no need to enter any value - just select the radio button.

To test the application in its classic ASP.NET MVC Framework form, select Start Debugging from the Visual Studio Debug menu. You'll see a (slightly weird) all-in-one layout that provides the user with a list of current bookings along with the ability to create and delete them:

In the next article we will add Web API facilities to our application.

The term "single page application" (or SPA) is commonly used to describe applications that were created for the Internet. These apps are accessible through a web browser like other websites, but offer more dynamic experiences reminiscent of native mobile and desktop apps.

The most noticeable difference between a regular site and an SPA is the reduction in the number of page updates. Spas have a heavier use of AJAX - a way to communicate with backend servers without complete update pages – for loading data into our application. As a result, the process of rendering (building) pages happens primarily on the client side using JavaScript.

SPA, Single Page Application

While building SPA applications is trendy and considered a modern development practice, it is important to be aware of its disadvantages, including:

  • The browser does most of the heavy lifting, which means performance can be an issue - especially on less capable mobile devices.
  • Complexity search engine optimization(SEO), the difficulty of delivering your content search engines and sites social networks, which provide link previews.
Mitigating Disadvantages with Server-Side Rendering

Most modern JavaScript frameworks work on how to handle SPA server rendering, i.e. the user will receive a fully populated page when the SPA is loaded for the first time, instead of seeing a loading indicator for example.

Server-side rendering can alleviate some of the blog work that browsers have to do when rendering pages, and can also help with SEO and content accessibility issues.

Popular JavaScript frameworks and libraries for creating SPA

The more interactivity that happens on the client side, the more JavaScript code is required to make those interactive elements function well. And the more code is written, the more important it is to have a clean and well-designed codebase. And this is exactly the problem that JavaScript frameworks solve, each with its own approach.

There are many open source JavaScript frameworks that help you create SPA applications such as.

  • Tutorial

Single Page Applications (SPAs) have many advantages, such as speed, really good UX, and full control of the HTML markup. There are more and more SPA sites; There are more and more tools that simplify the SPA development process. You've probably already read about the young and promising framework Vue.js. I suggest you dive deeper into Vue and use a specific example to understand a simple SPA.

We will write client-server application the simplest blog. The application will display a list of entries as well as the full text of each individual entry. And of course, all this will happen without reloading the page.

After reading this example application, you will learn how to extract data in Vue, create routes, and understand an interesting feature of Vue - single-file components.

Backend In this tutorial, we will mainly focus on the frontend in Vue. We won’t think about writing a REST backend. For example, we will use the service jsonplaceholder.typicode.com providing a stub in the form of a REST API. FrontendTools Getting started with Vue is very easy. With the right tools it's even easier. I recommend taking a look at the vue-awesome project, which contains a list of tools, components, libraries and plugins for all occasions. Vue-cli When creating a new project, it is recommended to use Vue-cli. This way you can create projects using the official Vue template projects, or one of the many open source template projects, and of course you can create your own and use it anywhere.

So, first, let's install vue-cli as a global package:

$ npm install -g vue-cli
Then we initialize the project with the selected template; For our example, using webpack-simple is more than enough.

$ vue init webpack-simple vue-spa
Next, go to the vue-spa folder and run npm install in the terminal. After installing all the packages, we can run our application in development mode.

$ npm run dev
This command will automatically run our project on the local webpack dev server. Our simplest Vue application will appear in the browser. Of course, it doesn’t look at all like we would like, and is only suitable as a starting point for starting something bigger. To continue working, I suggest you first familiarize yourself with the structure of our template.

Internally, the webpack-simple template has the following structure:

File index.html contains simple HTML markup with a single “app” element in the body. It will be replaced with the DOM generated by vue. For this reason the tag body It is not recommended to use as a root element.

In a folder src lies the main.js file, which contains the webpack entry point. Vue components are imported there. It also describes the root instance of Vue, which so far has two properties. The 'el' property provides a Vue instance with an association with the specified DOM element. Another one is a rendering function that generates the DOM from App.vue. All in all, that's all we need to know about webpack-simple template structure, not much, right? The main part of our application will be programmed in App.vue. The .vue extension identifies the file as a single-file vue component. This is one of the features of Vue that we will now take a closer look at.

Each *.vue file consists of three types of blocks: , and optionally . As a result, we can divide the project into related components. Within a component, its template, logic, and styles are intrinsically linked, and combining them actually makes the component more cohesive and easier to maintain. Now we are ready to start creating a blog in Vue.

Let's see what we are actually going to implement. We will have a header with our blog name at the top of the page. On the left side we will have a fixed sidebar, in which we will display the titles of our posts, it will be something like a table of contents. The rest of the page will be occupied by a dynamic block in which the post text itself will be displayed.

Step 1 First of all, let's remove all the extra lines from App.vue. And we will rewrite the template in accordance with our requirements.

Vue.js SPA
Secondly, we will create a Vue instance with a data property, which we will place in an array with our messages. At the moment it is empty, but soon we will place the data received from the server inside the array.

After the first call, you will no longer be able to add reactive properties to the root data object. Therefore, before creating a Vue instance, it is recommended to declare all reactive properties at the root level.

export default(data()(return(posts:)))
You can also add some styling to make the app look better.
The application code is hosted on github.com. It is enough to clone the repository and switch the branch by step number to trace the development of the application step by step, for example:

$ git checkout step-1
At the moment we have absolutely nothing to display in our navigation bar, so let's get the data from the server. For this I chose Axios, an easy-to-use HTTP client. You can also use any method you like, such as a Vue resource or a custom fetch or even jQuery Ajax.

Step 2 Install Axios

$ npm install --save-dev axios
Then we import it into the App component and define the getAllPosts() method which will make a request to the server and assign it to the posts property. We call the method in the created() hook, which will be called after creating a Vue instance and after setting the data access settings.

Import axios from "axios" export default ( data () ( return ( posts: null, endpoint: "https://jsonplaceholder.typicode.com/posts/", ) ), created() ( this.getAllPosts(); ) , methods: ( getAllPosts() ( axios.get(this.endpoint) .then(response => ( this.posts = response.data; )) .catch(error => ( console.log("----- error-------"); console.log(error); )) ) ) )
Now let's display all the post titles in the sidebar.

((post.title))
So far we have only displayed post titles, but we can't yet see the posts themselves. Now you need to display the full post in the content section according to the selected title in the sidebar. At the same time, I would like each entry to be available at its own unique address.

Step 3 To do this, we will use the official Vue library vue-router. As the name suggests, the library allows you to configure routing for our application.
Let's install the library:

$ npm install --save-dev vue-router
To configure routing, let's return to the main.js file. Here we will define the routing settings and add them to our Vue instance.

Import Vue from "vue" import Router from "vue-router" import App from "./App.vue" import Post from "./components/Post.vue" import Hello from "./components/Hello.vue" Vue. use(Router) const router = new Router(( routes: [ ( path: "/", name: "home", component: Hello, ), ( path: "/post/:id", name: "post", component: Post, props: true, ] )) new Vue(( el: "#app", render: h => h(App), router ))
In the routing settings, we specified which component causes rendering along the corresponding path. Since only the Post.vue component will be responsible for rendering each post, we won't need to define the path to each post, just define a dynamic path.

Path: "/post/:id"
This path contains a dynamic segment:id which points to a specific post. Moreover, we have access to this segment in the Post component via this.$route.params.id. However, using $route in our component will hardwire it to the route, which in turn limits the component's flexibility since it can only be used on certain URLs. Instead we can use the option props and install it in true. After this, $route.params will become associated with the props option of the Post component.
Now that we've created the router, we can go back to our application and add a few more lines to the template.

((post.id)). ((post.title))
Here we have two components vue-router: And . The first is a component for enabling user navigation in a routing-enabled application. The second component is a functional component that renders a consistent component for a given path.

The final step remains. We need to display the contents of the post entry.

Step 4 Let's move on to the Post.vue file, in which we will add a simple template:
((post.title))

((post.body))

((post.id))


Next we need to set the Vue instance parameters for this component. Everything here is the same as in the settings for displaying all posts. Let's declare an option props with changing id, which will receive our post number. Next, let's declare a data object, as we already did in App.vue:

Import axios from "axios"; export default ( props: ["id"], data() ( return ( post: null, endpoint: "https://jsonplaceholder.typicode.com/posts/", ) ) )
Then we will describe the method getPost(), which will receive only one post entry by id and call it in the hook created().

Methods: ( getPost(id) ( axios(this.endpoint + id) .then(response => ( this.post = response.data )) .catch(error => ( console.log(error) )) ) ), created() ( this.getPost(this.id); ),
Almost ready. If we run the application now, we can see that although the URL changes, we see the single post that was rendered first. The fact is that we have the same component to render different posts, and Vue does not need to recreate it due to unnecessary waste of resources, which also means that hooks life cycle components will not be called.
To fix this we just need to set a watcher on the object $route.

Watch: ( "$route"() ( this.getPost(this.id); ) )
Now everything works as it should. To get the production version, just run the command npm run build in the console.

Let's summarize We wrote a simple single page application using Vue in four steps. We learned how easy it is to start your project with vue-cli. We've covered the concept of single-file Vue components that make your project more flexible and scalable. We learned how to retrieve data from an external API using Axios. And we saw how to configure routing using vue-router. Of course, this is basic knowledge, but I hope this will help you get started using Vue.js and taking advantage of its advanced features.