I'm developing a single page application using angularJs with a layout page that will be available for all my pages, but now I want some pages to be loaded without the layout page included in it, how can I do that. Any idea on this. Remember my pages are not #razor rendered with .cshtml except the layout and the index page all the other pages in my app are .html files.
Index.cshtml:
<div data-ng-view></div> - This is where all my pages will get loaded in to using the ngRoute
_Layout.cshtml:
<body>
<aside><nav>....</nav></aside>
<section><header>...</header>RenderBody()</section> - This is where my index page gets called
<aside>....</aside>
</body>
Now, I would like to get my page still loaded through the #index as my application is SPA, but _Layout.cshtml should be ignored.
Any *.cshtml pages are rendered server side and then served to the client.
*.html pages are statically served to the client.
Usually any static resources are put in the "Content" folder. In my own personal project this is where I put my static html pages.
In other words, you are in fact using Razor. In this case, using a different _layout.cshtml is answered in this stackoverflow question:
How do I specify different Layouts in the ASP.NET MVC 3 razor ViewStart file?
Also, usually, in general, for an SPA app, data is served asynchronously through a REST API or a REST/JSON API. In which case, once you're layout is loaded client side, you shouldn't have to deal with *.cshtml files, you should only have to deal with pure data and your javascript on the client side takes care of rendering that data into html.
In my personal project, I have a HomeController that serves a static html page:
public class HomeController : Controller
{
public ActionResult Index()
{
return Redirect(Url.Content("~/Content/index.html"));
}
}
What happens here is that when the user goes to http://localhost/ it executes the Index action from the HomeController which redirects to a static html file that contains my layout.
Any requests after that are loaded using Ajax requests that return JSON data. In other words, for any following requests, I don't have to deal with Razor "*.cshtml" files.
You shouldn't need to "ignore" _layout.cshtml since you're suppose to be serving just data.
Related
Case Study
Consider the following scenerio:
I have a Node-Express server
The server renders a new .html file for every page and sends it to the client
Within each .html file:
there is some dynamic content filled in with EJS (such as the user's name in the navigation bar),
and part of the page (inside a <div id='app'></div>) is a React App (for instance, a table view with filters).
ReactJS, ReactDOM, and my React code is imported using <script src="___.js"> tags
Every time the client clicks on a link to go to another page, the server handles the routing and generates a new .html file that has
some dynamic content (e.g. user name in navbar)
A div containing a new React App, with the react code imported in script tags
Question
My question is Am I right to say that when it comes to Routing, this application uses "Server-Side Routing" and as for Rendering, a mixture of Client and Server-Side Routing?
Regarding your questions #2 and (perhaps) #3:
I would distinguish between static content, which is the same for all users of an app, and dynamic content, which depends on the user and can also change over time.
Server-side rendering is when the server produces HTML page that contain dynamic content. Such pages cannot be cached (at least not in a public cache, and even a private cache would have to be invalidated as the content changes over time). A further consequence of server-side rendering is that the whole HTML page must be reloaded when the dynamic content changes.
An alternative approach is a static (cacheable) HTML page that loads and renders all dynamic content with Javascript code (AJAX). This leads to pages that build up over time, as the dynamic content is loaded, and the "time to visual completeness" can become an issue.
Your approach sounds like a compromise where HTML pages contain some dynamic content, whereas other parts of the dynamic content (that change more frequently, I assume) are handled with AJAX methods.
I am developing a web app that has a sign in page for signing in. But also, for example, there is a public page for facebook sharing page.
If a user wants to go into the panel, url is:
http://127.0.0.1:3000/#/shops/:id/
If someone makes a Facebook share, we have a public page like:
http://127.0.0.1:3000/#/public/56af5229d0ae74e324c662f9
My problem is, I have 1 index.html for this app, and it includes css, js links and a ui-view for ui-router. For public page, all those unnecessary files are loaded.
In index page, I have:
<div ng-if="isPublic()" ng-include="'views/public.base.html'"></div>
Also, I cannot control the meta tags of the page.
How you can handle separation of pages in such a case?
I have a site with public/private parts, but I took a different approach in terms of resources. I did not separate them since it would be just to much work, instead I did this:
Minification
Bundling
Pre-compressing
Caching-forever with the hash-string
Putting all the html templates in a js bundle
Yes, this will make all the js/css that is not needed for everyone to load, but you can think of this as a standalone application: you have to download the whole executable/package and install it but you don't use all the functionality (e.g. think of Office). If you optimize all as much as possible, the few additional kilobytes won't do any difference and the data will be already there when the user logs on to private part.
P.S You can see how to do some of the points in here.
I intend to build a typical information website that has a number of pages that do not require authorization to view them, however I also want to have a private section for staff to log in. For simplicity I am hoping I can do one Web API project and have everything within it to simplify my publishing to azure, simplify domain names and certificates etc.
Is it ok for me to have index.html as a container and use ui-router to navigate through even the public pages or would it be better to have all public pages as full html files and do typical href navigation between them?
Below is the possible structure I was thinking of
app/ -> all angularjs stuff including private views and controllers
Models/
Controllers
Index.html -> public home page
public/ all public pages
What I am trying to achieve is that all public views can be accessed via http but once the login page is accessed all traffic must from then on be https, does anyone have any experience of this?
Update:
I have decided to force https for all pages, does this take the structure worry away in that everything just goes under app?
Best way to keep this is as a full Angular SPA, using ui-router to move between views instead of having static pages (even if your partial views are just plain HTML without functionality). You can affect the UX by alternating between dynamic routing with Angular and typical old href navigation. The less the you make the user reload pages, the better user experience he/she will get, plus you must be consistent in the way the application flows overall so the user doesn't have bad impressions of it.
I'm asking this because a couple of times now, I've tried to play around with the $locationProvider.html5Mode(true) command along with <base href="/"> and ran into a lot of errors calling the scripts/styles/images for my project. I guess there must be something I am doing wrong, but is there a certain folder structure you should follow so you don't run into these errors? Or is there a specific way that the base href works that I'm not quite understanding?
Recently, I thought I'd try it on a very, very small app. It's effectively a static website, but I want to take advantage of Angular's routing to make sure all of the pages can load instantly. So my structure would be something like this:
my-project
css
images
js
angular
app.js
app.routes.js
mainCtrl.js
views
home.html
about.html
contact.html
index.html
So I know that this folder structure isn't great, but I'll only be using Angular in this project for routing, nothing more, so it fits my needs.
I put into the head <base href="/">, put in body ng-app and ng-controller, and inside the body put a <div ng-view> somewhere too.
I added in the $locationProvider.html5Mode(true) and tried the app out. All of my scripts are then being loaded as http://localhost:8888/script.js which is incorrect. The project is located in a folder so that index.html is located in http://localhost:8888/my-project/index.html. So, it should be loading the scripts from http://localhost:8888/my-project/js/angular/app.js for example.
Is there something that I'm not understanding about the base href? Eventually I may host this app somewhere online, so I want the URLs to scripts etc to all be relevant to the file really. Anyone have any ideas?
Alright, so above the base href tag I would have my CSS styles which would be linked as css/style.css and at the bottom of my body tag I would have my scripts loaded as js/init.js or js/angular/app.js for example. This would try to load it as if the js folder is located directly at localhost:8888/js.
The Angular framework is a Single Page Application (SPA) that is able to run in a browser by essentially tricking the browser into running code snippets rather than make server calls, by making use of the "hash" (#) page anchor. Normally, a URL with a # would jump to a specific anchor point in the page; in the case of Angular or other similar SPA frameworks, the # is redirected to a code segment instead.
Ideally, you would like to not have to reference this # in your page URLs. This is where Html5Mode comes into play. Html5Mode is able to hide the #, by using the HTML5 Push State (aka history API).
When Html5Mode is enabled, the normal links on the page are silently replaced by Angular with event listeners. When these events are triggered, the current page is pushed into the browser history, and the new page is loaded. This gives the illusion that you are navigating to a new page, and even allows for the back button to operate.
This is all fine when you are dealing with links which are clicked from within the running application, but relying on event listeners can't work if you navigate to the page from an external source, where Angular isn't loaded into memory yet. To deal with this, you must be loading your pages from a web server which supports URL rewrites. When the server receives a request for a URL that there isn't a physical page for, it rewrites the URL to load the base HTML page, where Angular can be loaded and take over.
When Angular receives a request for a route which has been rewritten in this manner, it must first determine what the intended route was. This is where the Base HTML Tag comes into play. Angular uses the Base reference to help it to determine which part of the URL is on the server, and which part is a client route. Essentially, where the # in the URL would be if Html5Mode was not enabled.
Unfortunately, Base is an HTML Tag that is used by the browser for more than just Angular. The browser also uses this tag to determine the correct location to load scripts and resources using relative paths from, regardless of the path in the location bar. In general, this isn't a problem if all of the scripts and resources are relative to the location of the Index.html file. When Base is omitted, the browser will load scripts from the apparent base path determined by the current URI. However, once you provide it, the browser will use whatever value you have supplied.
In general, unless you are hosting angular on a sub-page of your site and you want your users to expect something specific in the URL string, you should always control the base on your server, and use Base="/" on the client side.
I'm creating a web application in which the bulk of the functionality is deployed as an AngularJS single-page application, but there are also a few static content pages that are served in the traditional way.
Navigation within the SPA employs Angular UI Router and seems to be working correctly, as does the serving of the static pages.
However, the code architecture is such that all scripts are referenced from within the main site template and are thus served with every page, including the static pages. This is a deliberate decision, as there are some scripted features that need to accessible from everywhere, even from within the static pages.
For example, the header region of every page contains a search box with typeahead, that allows users to navigate to a view within the SPA, populated to reflect the selected content.
If a search is invoked from within the SPA, everything works as expected, and the routing mechanism correctly executes the required state transition to render the selected content. However, if the same search is conducted from within one of the static pages, although UI Router correctly processes the state transition, the content is not rendered because the static page does not contain the <ui-view> element that is usually targeted by rendering.
Although I can see what's causing the problem, I'm not sure how best to resolve it. From a novice perspective, it seems that I need to intercept the content search/selection process and execute different logic, depending on whether or not the search was invoked from within the SPA or a static page. I anticipate something like this:
if ($state.current.name) {
// The search was invoked from within the SPA, so only a state change is required.
$state.go("render", { key: selected_key });
} else {
// The search was invoked from a static page, so an SPA page load is required
What can we do here to bypass routing and issue a
server request for the corresponding SPA deep-linked page?
}
But I'm willing to guess that there is a more elegant way of dealing with this issue, maybe one that's baked into Angular UI Router.
Any suggestions please?
Many thanks,
Tim
For anyone facing a similar problem, the solution is actually very simple.
Instead of attempting to intercept and coerce the state transition, the desired behavior can be achieved through a simple modification to the main page template, enabling all pages, including static pages, to participate in Angular view rendering.
In my original implementation only the SPA page used the <ui-view> element, which resulted in the static pages ignoring the rendering that typically occurs during a state transition.
To solve the problem, I eliminated the <ui-view> element from the SPA page and, instead, added a ui-view attribute to the containing element in the main page template:
<html ng-app="myApp">
<head>
... page head content goes here ...
</head>
<body ng-controller="myController">
<div ui-view>
... server-generated page content is injected here ...
</div>
... page scripts are referenced here ...
</body>
</html>
With this change in place, every page is now effectively an SPA and capable of re-rendering to reflect state transitions (albeit that most of the time this never occurs, since the user simply views the pre-rendered content that was delivered by the server).