How can I refresh the data in a handlebars view? - node.js

I am working on a project, part of which displays notifications to the user. I have an object which is used to store notifications, and a table in which notifications are displayed. The notifications are written to a JSON file in a proper format for later use.
Currently the way things are, the object has new notifications pushed to it every x seconds, but the actual table only displays the new messages when the page has been reloaded.
I am looking for:
A way to programmatically refresh the data maintained within the table every x seconds.
Or:
A method like webhooks or socket that I can use to send the new object direct to the client.
A method of refreshing the web page every x seconds, without the use of a module like nodemon, which actually kills and resets my server completely.
The JSON File
[
{
"Notification": "Limit Exceeded. Event has occurred. Action needed.",
"Time": "19:54:34",
"Date": "Sun Oct 28 2018 "
},
{
"Notification": "Limit Exceeded. Event has occurred. Action needed.",
"Time": "19:54:34",
"Date": "Sun Oct 28 2018 "
}
]
The JSON file starts empty, and has notifications logged to it. The notifications are pulled from here, and stored in an empty notifications object.
The Handlebars View.
<h2 class="page-header">Notifications</h2>
<h2>{{log}}</h2>
<p>Your Latest Notifications can be Found Below.</p>
{{#if notifications}}
<table style="width:100%" border="1">
<tr>
<th>Notification:</th>
<th>Time:</th>
<th>Date:</th>
</tr>
{{#each notifications}}
<tr>
<td>{{[Notification]}}</td>
<td>{{Time}}</td>
<td>{{Date}}</td>
</tr>
{{/each}}
</table>
{{else}}
<h3>No Current Notifications</h3>
{{/if}}
<form method="post" action="/test/notify" id="removeuserform">
<button type="submit" class="btn btn-default">Reload page.</button>
</form>
And the page of course is rendered using the following line.
res.render('home', {notifications: notifications});
The solution?
I have looked into many a method here, and would love to see your opinions as well. I have seen people use webhooks, I have seen people initialize a button click which redirects to the same page. I cannot use the window.reload function. I have seen people place tags in EJS views, but I am using Handlebars.
Is there a way to simply refresh the data in this notifications object when I push new items into the object? Any ideas you have are greatly appreciated. Thank you in advance.

I think you need to care about 2 parts:
1, Get data from server in real-time via socket. Here you have 3 options:
SocketIO or similar Node.js package
A service such as Pusher, Firebase...
A database that support data syncing, such as PouchDB, Gun, etc
2, Sync data from JavaScript object to view. This calls data binding. Basically, you have a JS object that contains your notifications. And you render that data to HTML, display them to end-user. When that JS object changes, your HTML should be automatically updated. That's one-way binding, from JS object to DOM (model to view). Many UI frameworks or libraries can help you here. You may choose a small tool, such as HyperApp, AppRun, Mithrill, etc.

Related

handlebarsjs get the value of the selected option dynamically

I've been working with pug/jade a little bit and now I'm trying to build the same project using handlebars.
I have this iteration that renders a few options:
<select id="myselect" name="myselect">
{{#each categories}}
<option value="{{id}}">{{title}}</option>
{{/each}}
</select>
A bit further down the code I need to render some items dynamically based on the selected item from myselect.
Any idea how I can grab it dynamically? Basically the same way like onchange() works in plain javascript.
When you use any kind of tempting engine (handlebars, jade, ejs, etc). You cannot bind data after the response sent to the client. You have to write some client side javascript code to achieve that.
As an alternative you can use handlebarjs on client side. Follow this link
But this may need to be used carefully, since you are using the same template engine on your server side.

Set parameter for URL in html and use parameter in Node.js Express for routing

I very much new to Node JS and Express Framework & mongodb. I am working on a website which has multiple categories and when we click on category it goes to a view, where based on the category clicked, data gets loaded in the view.
please check the link for website here.
I am looking help for navbar links eg. Montessori Premium->Toddler Material
As these are static links I can not figure how to pass any parameter or url format for this.
I have done the routing for individual products as they have ids coming from database so I am using that id in url.
Thanks in advance.
It seems to me like you're just missing a bit of glue in between the front-end and the back-end database calls. Here's a rough idea of the sequence you might be after and an explanation of what I think you're missing.
If I'm wrong, please add a comment and update your question to include the new details and I'll see about editing my answer.
In this example I'm creating a website which has a list of "items" in a shop and we're looking to display them all on a single page. Each item should then have an a href clicking through to that specific item where there might be more detail such as a "full description" of the item and maybe some images or something. We're going to look at the flow to build that first page with the list of items.
The user makes a HTTP GET call to the root of your website such as "http://www.mystore.com/".
This request comes through in Express to your controller which takes the req, res, next parameters.
Your controller makes a call to the database to get a list of all items including their names and ID's.
You then use something called templating to inject in the list of items.
In this template you iterate through the list doing something like this.
.
<ul>
{{#each items}}
<li><a href="/items/{{id}}>{{name}}</a></li>
{{/each}}
</ul>
In this template (which happens to be Handlebars), we're going through the list of items and using the id and name of each to inject them into the HTML to get something a bit like this back.
<ul>
<li><a href="/items/1>Shoes</a></li>
<li><a href="/items/2>Red spotted dress</a></li>
<li><a href="/items/3>Jeans</a></li>
</ul>
This is then served up to the user once the template has been processed.
In essence I think you're after some sort of templating engine, I'd highly recommend having a look at Handlebars with something like the express-hbs.
Thank you #Elliot for your time to answer this. Yes I am using handlebars for templating. The solution I found is, because I am using static links, I am passing query string in anchor tag link.
eg. http://localhost:8000/product?category=Toddler_Material
and then using req.query for capturing the values (Toddler_Material) in router
var category = req.query.category;

Render data from node server on page refresh and thereafter from angularjs

I'm developing an app using angularjs with nodejs and dustjs.
What i'm trying to achieve is like during the page refresh pass the data like
res.render('index', {names : [{name:"name1"},{name:"name2"}]});
and dustjs should able to render
{#names}<li>{name}</li>{/names}
how can i use angular js ngrepeat for subsequent actions in the page.
As of now i'm making a http request get the json and render page fully in client side.
<li ng-repeat="myname in mynames>{{myname.name}}</li>
I don't prefer to save my data as JavaScript variable, which is readable through source.
Just want know if somebody done something like this.
I done it in a hackish way to implement this, not a suitable solution.
I used ng-if of angularjs to do this
var mynames = [{name:"One"},{name:"Two"}]
<div ng-if="!mydata">
{#mynames }
<div>{name}</div>
{/mynames }
</div>
<div ng-if="mydata">
<div ng-repeat="myname in mynames">[[myname.mynames]]</div>
</div>
i'm using square brackets for angularjs as there was some conflict with dustjs which was fixed using below code
angular.module('myapp').config(function($interpolateProvider){
$interpolateProvider.startSymbol('[[');
$interpolateProvider.endSymbol(']]');
});

Meteor Iron-Router Layout Rendering

We have implemented a layout where the main content resides in dynamic sidebars. We defined following layoutTemplate:
<template name="layout">
{{> content}}
{{> leftbar}}
{{> rightbar}}
<nav class="navigation">
{{#if currentUser}}
{{> navigation_logged_in}}
{{else}}
{{> navigation_logged_out}}
{{/if}}
</nav>
</template>
We include e.g. the rightbar template in the layout template.
<template name="rightbar">
<aside class="rightbar">
<button id="closeRightBar" class="close-cross"></button>
{{yield 'rightbar'}}
</aside>
</template>
The rightbar template includes the rightbar yield where we yield the specific content into.
We have implemented following RouteController:
UserShowRouter = RouteController.extend({
before: function() {
var username = this.params.username;
if(App.subs.user) {
App.subs.user.stop();
}
App.subs.user = Meteor.subscribe('user', username);
},
waitOn: function () {
return Meteor.subscribe('user');
},
data: function() {
return Meteor.users.findOne({'profile.username': this.params.username});
},
action: function() {
this.render('profile', {to: 'rightbar'});
}
});
What we wanted to achieve is that for example the profile template is yielded into the rightbar yield and get's updated and re-rendered as the data changes.
The problem is now that the sidebars are dynamically animated, shown and hidden. Now every time the profile template gets re-rendered also the layout template gets re-rendered. Why is that? We thought one of the purposes of yield regions is that the whole site doesn`t need to be re-renderd. Now when the layout gets re-rendered the whole css of the animations are set back to the original values.
We now have tried several different approaches, but none of them seems to be a good and clean solution. Is there a way to keep the layout template from being re-rendered and just keep the yield region and template up-dated? Any suggestions or alternatives would be highly appreciated.
As I understand it, the behavior in which re-rendering of your templates "bubbles up" and causes re-rendering of their parent templates is not particular to iron-router or the way your code is implemented, but is inherent in Spark. Iron-router's {{yield}} pattern does not alter this behavior, as far as I can tell from its documentation.
The good news is that Spark is set to be replaced imminently with a newer, more fine-grained rendering engine, currently codenamed "Spacebars," which should alleviate the concern.
Here is a preview of the new rendering system:
https://github.com/meteor/meteor/wiki/New-Template-Engine-Preview
This talk from a week ago is also excellent at describing the benefits coming through the new rendering engine (while fairly long, an overview is given in the first 5 minutes):
https://www.youtube.com/watch?v=aPf0LMQHIqk
As for your options today, you can:
a) Use the {{#constant}} and {{#isolate}} parameters to try to limit re-rendering.
b) Work from a development branch as described in the link above:
You can play with the current work-in-progress version of the code using the template-engine-preview-4 release tag (run your app with meteor --release template-engine-preview-4), or by checking out the shark branch (it's an internal codename).
c) Best of all if the timeframe of your project allows is to allow the re-rendering to continue until Meteor 1.0 hits and "Spacebars" resides on the main branch - it sounds like this is 1-3 months away.
I think that the reason your layout template gets rerendered is because the data hook you implemented uses a reactive data source. If the current user object changes, the router probably decides to rerender the whole page because there is no simple way to decide which parts exactly depend on your reactive data.
If I'm right, a simple solution to your problem is to create a user helper that will fetch the necessary data only where they're actually needed, e.g.
Template.profile.user = function () {
return Meteor.users.findOne({/*...*/});
}
Then you can use it in your profile template along with the with helper (sic!), i.e.
{{#with user}}
...
{{/with}}
to prevent multiple calls to the Template.profile.user function.
Also, if I were you, I would use the data hook only for data which is required by templates in my layout.

Passing arguments from node.js to knockout.js through ejs

I have a node.js that consumes mongodb data and outputs lists using knockout.js
When i invoke the view i pass a json structure using
res.render('list', { items:json });
In the list.ejs template page i've defined a hidden element:
<input type="hidden" id="hidden" value="<%= items %>">
and in .js file i read its value:
var json=$("#hidden").val();
var tkts=jQuery.parseJSON(json);
var vm=new AppViewModel(tkts);
Well...it runs but i think (hope) there must be a better way do it ... is there a way to avoid a hidden html var, for example?
Currently I can think of three ways to do this.
1.) Assign the data to a variable in your JavaScript code:
<script type="text/javascript">solution1 = {"name": "solution1"}</script>
solution1
2.) Add a data-attribute to an element of your liking:
<div id="solution2" data-value='{"name": "solution2"}'></div>
JSON.parse(document.getElementById('solution2').dataset.value)
3.) Use the script tag and choose a different content type than text/javascript or application/javascript
<script id="solution3" type="script" type="text/json">{"name": "solution3"}</script>
JSON.parse(document.getElementById('solution3').innerHTML)
Live demo
http://jsfiddle.net/bikeshedder/sbjud/
Personal note
It might sound boring, but the first option is probably the best choice. It is fast, requires as little code as possible and just works. I don't see a reason why you would want to have your data in a string first if you can have it as JavaScript data right away.
You could add an inline script if you are serving up a full page... Of course this would pollute the global namespace.
<script>
var tkts = <%= items %>;
</script>
If you are using AJAX to get this page... then break it into two AJAX requests... one of them gets the template, and the other one can get the list of items (as a JSON request). They could run in parallel so it might even be quicker.

Resources