Express.js Avoid reload the whole page - javascript

currently I have no solution for a site which I am trying to build. The page is not that big but I want to achieve that the complete site does not reload when I am opening a new tab in the navbar. I am using express.js and mustache as the template engine.
My goal is, that only the content reloads and not the whole site including the Navbar.
Do I have to use Ajax here? and
Is my structure correct to do this?
On the Server.js file I have this general structure I am not sure if there is a trick with views to only reload the content part of a page:
app.get('/home', function(req, res) {
res.render('index.html')
});
app.get('/navitem1', function(req, res) {
res.render('navitem1.html')
});
app.get('/navitem2', function(req, res) {
res.render('navitem2.html')
});

If you are trying to make sure your webpage doesn't reload while switch tabs and you're webpage isn't that big. I would recommend containing all your information within one .html file, have each "page" contained by a div with a targetable id, then simply hide/show the content that is selected. You might want to check out page.js and jquery they make this process much easier.
This is a quick demo of how to implement this:
note: you will need to npm init and npm i page
index.html:
<html>
<head>
<title></title>
</head>
<body>
<div id="title-area">
<h1>--your title--</h1>
<nav>
<ul>
<li>Home</li>
<li>Another Page</li>
</ul>
</nav>
</div>
<div id="home">
--home content--
</div>
<div id="another-page">
--other page content--
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="vendors/scripts/page.js"></script>
<script src="scripts/controllers/routes.js"></script>
</body>
</html>
scripts/controllers/routes.js:
sorry about globally scoped the IFFE functions, this is copy pasted.
'use strict';
(function(module){
const homeController = {};
homeController.init = function(){
$('#another-page').hide();
$('title').html('Home');
$('#home').fadeIn('slow');
}
module.homeController = homeController;
})(window);
(function(module){
const anotherpageController = {};
anotherpageController.init = function(){
$('#home').hide();
$('title').html('anotherpage');
$('#another-page').fadeIn('slow');
}
module.anotherpageController = anotherpageController;
})(window);
page('/', homeController.init);
page('/anotherpage', anotherpageController.init);
page();
if you'd like a better demo you can check out the app I built (where most of this content was ripped) https://github.com/loganabsher/portfolio-2.0

Related

How to create an html header for every file in a project using javascript?

I'm working on a simple GitHub pages site using HTML and javascript. Since pages do not offer support for PHP or SSI includes for an HTML header from a separate HTML file, I need to write a script which will create the header images an establish the links in the menu ribbon.
Suppose for the sake of understanding this website is composed of three files whose paths are:
root/index.html
root/A/pageA.html
root/B/pageB.html
The header should have a link to each of these files.
The only solution I have been able to come up with is to use these in all files:
<a href='https://somewhere.something/index.html'>Index</a>
<a href='https://somewhere.something/A/pageA.html'>A</a>
<a href='https://somewhere.something/B/pageB.html'>B</a>
I just was unsure if this is good practice!
If there is a way to accomplish the same effect which is more conventional I would love to hear it.
Below SO snippet not works, but here is working example - click on left menu, look into page source)
async function load(url) {
let html = await (await fetch(url)).text();
pageBody.innerHTML = html;
}
let page = location.search.substr(1) || 'index';
load(page + '.html');
<h1>My site</h1>
<ul>
<li><a href="?index" >Main</a></li>
<li><a href="?A/pageA" >A</a></li>
<li><a href="?B/pageB" >B</a></li>
</ul>
<div id="pageBody">
You can make use of HTML Imports.
The <head> section that you place on each page would reference a single import file:
<head>
<link rel="import" href="/path/to/import.html">
</head>
With your import file containing what you want to load into each page's <head> section:
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
Note that the import file should not contain <head></head> tags itself, merely the contents.

MEAN stack - Error while loading AngularJS script

I'm 100% new to MEAN stack and currently trying to self-study it with the help of this video by Michael Moser (If you're reading this, thank you for making such an easy-to-understand video! :) ). I'm trying to make a very basic program with CRUD functionalities, but I can't get past this particular error message when loading the Angular JS file. Can somebody point me in the right direction?
Here are my codes:
package.json
{
"name": "starter-node-angular",
"main": "server.js",
"dependencies": {
"body-parser": "~1.4.2",
"express": "^4.5.1",
"method-override": "~2.0.2",
"mongoose": "~3.8.0"
}
}
server.js
// modules needed
// express - middleware
var express = require('express');
var app = express();
// listens for request to server and throws main.html as response
app.get('/', function(req,res) {
res.sendfile(__dirname + '/client/views/main.html');
});
// listens for request to server with 'scripts' in it and returns the appropriate file declared
// in the script tag
app.use('/scripts', express.static(__dirname + '/client/scripts'));
app.listen(3000, function(){
console.log("Ready...");
});
HTML
<html ng-app="ProductApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js" type="text/javascript"></script>
<script type="text/javascript" src="/client/scripts/main.js"></script>
<!-- stylesheets -->
<link href="/styles/main.css" rel="stylesheet" type="text/css">
</head>
<body class="main-background" ng-controller="MainController">
<!-- Area for Logo and Search Bar -->
<div class="header">
<div class="main-logo">
STUFF - Product Inventory v1.0
</div>
<div class="main-search">
<input type="text" class="search-field" placeholder="What are you looking for?" />
<img src="images/search-icon.png" title="Search" class="search-ico" />
</div>
</div>
<!-- Area for Add Button -->
<div class="add-container">
<div class="add-button" ng-click="addProduct(test);">
<img src="images/add-icon.png" title="Add" class="add-ico" />
<span class="add-text">Add Product</span>
</div>
</div>
</body>
</html>
AngularJS
'use strict';
var app = angular.module('ProductApp', []);
// Main controller
app.controller('MainController', ['$scope', function ($scope) {
// Search Products
$scope.searchProduct = function (param) {
// Search fxn goes here...
}
// Add products
$scope.addProduct = function (param) {
alert('Add product');
}
// Edit Products
$scope.updateProduct = function (param) {
// Update fxn goes here...
}
// Delete Product
$scope.deleteProduct = function (param) {
// Delete fxn goes here
}
}]);
I came from a background where calling JS files was simply declaring the full path in the src. Tbh, I find the entire MEAN setup a bit complex, with the "middleware" concept and all. :( I appreciate MongoDB's role in it, though.
Anyways, any help and advice would be greatly appreciated. God knows I need a lot of it right now.
Thank you.
Update 1:
I tried changing how my <script> tag calls my angular like so, with no success:
<script type="text/javascript" src="C:/users/myusername/documents/practice/product db/client/scripts/main.js"></script>
Also, am I right in thinking that localhost:3000 refers to Product DB in the following directory structure? I'm aware that 3000 is the port number; after looking at my error logs, I was thinking that localhost is just an alias for the source folder of the app.
Complete path is C:\users\myusername\documents\Practice\Product DB...
Thank you, as always. :)
You have included ng-app in the HTML tag, try adding that in the body of the page.
Do this:
<body class="main-background" ng-app="ProductApp" ng-controller="MainController">
Update:
you have done few mistakes while fetching stylesheets and scripts both. You need to define a proper static route which will work for all the static files(stylesheets and scripts).
you had defined yous static routed like this:
app.use('/scripts', express.static(__dirname + '/client/scripts'));
This will tell the node app to look into client/scripts folder, if any static route starts with /scripts. But you are trying to fetch your script using src="/client/scripts/main.js" which will not get anything, as /client is not defined , nor default '/' route is defined. It should be src="/scripts/main.js" instead.
One more mistake is while fetching stylesheets. you are using href="/styles/main.css", where again neither /styles nor / is defined, thus it will not be able to get the css file.
Try this instead:
Server.js
//define static routes like this
app.use(express.static(__dirname + '/client'));
// this will tell node app to look into the client folder, for any static file
HTML:
Fetch all your files like below:
To get stylesheets :
use /styles/filename
<link href="/styles/main.css" rel="stylesheet" type="text/css">
This will look into styles folder inside client folder.
To get scripts :
use /scripts/filename
<script type="text/javascript" src="/scripts/main.js"></script>
This will look into scripts folder inside client folder.

Refresh using Page.js gives 404 Not Found

I have just started using page.js, a routing library that I intend to use to make a single page application with handlebars. I will use the routes to call different handlebar templates. So far, this functionality is working and is as quick as I had hoped.
I am currently encountering an issue where refreshing the page (pressing F5) or copying the URL, and pasting it into a new tab gives me a 404 not found error. It is not calling the not found page that I created in my app.
The code below is a copy of: https://github.com/visionmedia/page.js/tree/master/examples/notfound
<!DOCTYPE html>
<html>
<head>
<title>Not Found</title>
<script src="/page.js"></script>
</head>
<body>
<h1>Not Found</h1>
<p></p>
<ul>
<li>/</li>
<li>/about</li>
<li>/contact</li>
<li>/not-found</li>
</ul>
<script>
page.base('/notfound');
page('/', index);
page('/about', about);
page('/contact', contact);
page('*', notfound);
page();
function index() {
document.querySelector('p')
.textContent = 'viewing index';
}
function about() {
document.querySelector('p')
.textContent = 'viewing about';
}
function contact() {
document.querySelector('p')
.textContent = 'viewing contact';
}
function notfound() {
document.querySelector('p')
.textContent = 'not found';
}
</script>
</body>
When I refresh this page, I am presented with my localhost's 404 page. I get the same result when I use the link http://127.0.0.1/notfound/about.
My question is this: does page.js support refreshing the browser, or using links to access specific portions of my application?
It seems that the question I should really be asking is this: Would it be possible for the web server to redirect all navigation to the page that loads the application? The answer is Yes.
It seems that refreshing the browser would be a common case. An acceptable solution to this would also be to catch any refresh attempts, and redirect them to the main page. Using links to access specific portions of my application is not as crucial, but would be a nice touch.

Perform a function based on the hash with director.js

I am trying to use director.js for the routing on my single page application. The issue is when you go to a page by typing it into the address bar the application does not perform the function that the hash in the routing table is pointed to.
Here is the example on github - If I refresh the page with a hash or direct to a page with a hash nothing shows up in the console. But if I click on one of the links console output is shown. How can I change this code so that if a user directly goes to a link the routing table checks the hash and performs it's matching function from the routing table? Please answer with a methodology that utilizes director.js
<html>
<head>
<meta charset="utf-8">
<title>A Gentle Introduction</title>
<script src="https://raw.github.com/flatiron/director/master/build/director.min.js"></script>
<script>
var author = function () { console.log("author"); },
books = function () { console.log("books"); },
viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); };
var routes = {
'/author': author,
'/books': [books, function() { console.log("An inline route handler."); }],
'/books/view/:bookId': viewBook
};
var router = Router(routes);
router.init();
</script>
</head>
<body>
<ul>
<li>#/author</li>
<li>#/books</li>
<li>#/books/view/1</li>
</ul>
</body>
</html>
I have not used Director but your issue may be the fact that GitHub serves the "raw" files with a mime type of "text/plain". So the Director js code might not be processed as javascript, causing your test page not to work. Try downloading your own copy of Director and link to the local version instead of the one on GitHub.

Javascript single page architecture with module autonomy

I just started this HTML5 project where we decided to make it a single page architecture by leveraging jQuery $.load() method. Unfortunately, as soon as the JS started to grow, we quickly started running into issues where the modules loaded into the master dashboard have no knowledge of their parent.
The architecture looks like this:
dashboard.html (master file)
moduleA.html
moduleA.js
moduleB.html
moduleB.js
moduleC.html
moduleC.js
Since we decided to also keep the JS as separate files, we are having to load all JS files through dashboard.html in order to invoke them individually when modulex is loaded.
So when loading moduleA.html into the dashboard we have to call its corresponding JS. To do this we simply wrote the JS using a Module Pattern so we can easily invoke it by doing a function call, like:
<script>
moduleA
</script>
or this if we want to access a specific property of this member.
<script>
moduleA.someMethod();
</script>
Now, I know there are is gotta be a nicer way of doing this, right? I hate having to have script tags in the HTML modules in order to load its corresponding JS file.
Another limitation of this is the fact that we no longer can work on modules individually, since the scripts and CSS invocation happens on the parent (dashboard.html) so certainly when moduleA.html is loaded directly, it is pure HTML with no script or CSS.
I looked through the other questions but I didn't see anyone with the same problem.
I looked at AngularJS, EmberJS, KO.JS and BoilerPlateJS but none of them addresses what we are trying to accomplish. The only one that has a similar single page concept is jQuery Mobile but I don't know if you can switch from jQuery to jQuery Mobile and everything remains working.
Has anyone face this issue yet? Is there a solution or would I have to go with a custom solution.
Thanks!
I could argue about AngularJS with you. It is exactly what you need
dashboard.html is layout with some directives attached, but power lies in AngularJs if you use ng-view directive
here is example:
dashboard.js
var app = angular.module("modularApp",[]);
app.config(['$routeProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
controller:'HomeCtrl',
templateUrl:'templates/home.html'
});
$routeProvider.when('/moduleA', {
controller:'ModuleACtrl',
templateUrl:'templates/moduleA.html'
});
$routeProvider.when('/moduleB', {
controller:'ModuleBCtrl',
templateUrl:'templates/moduleB.html'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
templates/dashboard.html
<html ng-app="modularApp">
<head>
<!--.... include angular minified js file and what else you need...-->
<script type="text/javascript" src="dashboard.js"></script>
<script type="text/javascript" src="moduleACtrl.js"></script>
<script type="text/javascript" src="moduleBCtrl.js"></script>
</head>
<body>
<a ng-href="#/moduleA">Open Module A View</a>
<a ng-href="#/moduleB">Open Module B View</a>
<!-- Add widgets header menus .... -->
<ng-view></ng-view>
</body>
</html>
moduleACtrl.js
var app=angular.module("modularApp");
app.controller("ModuleACtrl",function($scope){
$scope.scopeValue="Hellow from view";
});
moduleBCtrl.js
var app=angular.module("modularApp");
app.controller("ModuleBCtrl",function($scope){
$scope.scopeValue="Hellow from another view";
});
templates/moduleA.html
<div>{{scopeValue}} in module A</div>
templates/moduleB.html
<div>{{scopeValue}} in module B</div>
You can do more complex things with angular then just this. All depends on your needs. Do you have any special requirements :)
Also, you could create your own directive, like ng-view and use your own $route service and $routeProvider so you can add css and javascript you want to dynamically load when some rute match url.
so instead of above routing table, you could have
app.config(['$myRouteProvider', "$locationProvider", function routes($routeProvider, $locationProvider) {
$routeProvider.when('/dashboard', {
javascript:'javascript/dashboard.js',
templateUrl:'templates/dashboard.html',
cssfile: 'css/dashboard.css'
});
$routeProvider.when('/moduleA', {
javascript:'javascript/moduleA.js',
templateUrl:'templates/moduleA.html',
cssfile: 'css/moduleA.css'
});
$routeProvider.when('/moduleB', {
javascript:'javascript/moduleB.js',
templateUrl:'templates/moduleB.html',
cssfile: 'css/moduleB.css'
});
$routeProvider.otherwise({redirectTo: "/dashboard"});
}]);
But that is, pardon on my French, stup. There are couple libs I tried in ruby on rails to acheive similar, but backend is rendering content, or just part of content. But I'm not sure which backend you are using and are you interested to switch to rails anyway.
DomController in BoilerplateJS does what you need, without using any custom HTML attributes. Your dashboard.html can just have place holders where you want to inject your components. I'm just pulling out some html below from BoilerplateJS index.html to show how it works:
<body>
<section id="page-content">
<header>
<section class="theme"></section>
<section class="language"></section>
</header>
<aside>
<section class="main-menu"></section>
</aside>
</section>
</body>
theme, language and main-menu sections above are just place holders in to which relavant components would be injected by the DomController. The DomController can be now used to register the components with appropriate selectors as below:
//scoped DomController that will be effective only on $('#page-content')
var controller = new Boiler.DomController($('#page-content'));
//add routes with DOM node selector queries and relavant components
controller.addRoutes({
".main-menu" : new MainMenuRouteHandler(context),
".language" : new LanguageRouteHandler(context),
".theme" : new ThemeRouteHandler(context)
});
controller.start();
Above code is extracted from "/boilerplatejs/src/modules/baseModule/module.js"

Categories