How to display each element in an array from Node in HTML? - html

I'm using express to render a page in my node app and have sent an array to the client-side. I'm wondering how I can display each element as a paragraph in the HTML.
What I tried is below, but it does not work. When my results array is five elements long, I can see in Safari's Inspect Element that five p tags are created but they are empty.
Note that the results array was initiated and populated.
Node:
const app = express();
app.post('/home', (req, res) => {
...
// results array gets populated here
...
res.render('home', {results: results});
});
HTML:
<div class="results">
{{#each results}}
<p>{{r}}</p>
{{/each}}
</div>

That looks like you're using handlebars as your view template engine? If so, you've not define r at all.
Assuming results is an array of objects such as [{val: "hello"}] you can do {{val}} inside your p tag. If it's just a single value, not an object, then try using {{this}}.
For a complete example:
<div class="results">
{{#each results}}
<p>{{this}}</p>
{{/each}}
</div>
Or
<div class="results">
{{#each results}}
<p>{{val}}</p>
{{/each}}
</div>

Related

How to display json array data in html after using sendFile in node Js

enter image description hereI have an HTML file named as index.html.
The file contains a JSON array data as added below.
I want to display this array using div tag, The HTML code is given below :
Code
//node js code
res.sendFile(__dirname+'/index.html',{data:JSON.stringify(data)});
//html code
<% var d = JSON.parse(data); for (var i= 0; i < JSON.parse(data)[0].length; i++) { %>
<div class="col-md-12 mt-3 border-bottom p-2 chat-select ">
<div class="row">
<div class="user-chat-img">
<img src="img/user.jpg">
</div>
<div class="">
<p class="font-weight-bold"><%= d[0][i].name %></p>
<span>Hello I am DK Singha </span>
</div>
</div>
</div>
<% } %>
Please suggest me how to resolve this problem.
I found this.
res.sendfile in Node Express with passing data along
rewrite.
// NodeJS
const target = '$$$data$$$';
fs.readFile(__dirname+'/index.html', (err, html) => {
res.send(html.replace(target, JSON.stringify(data)));
});
// HTML
<script>
var data = '$$$data$$$$';
data = JSON.parse(data)[0];
for (var i= 0; i < data.length; i++) {
console.log(data[i].name);
}
</script>
this is working?
I suggest you to use view engine, such as twig, pug or blade. If you are working with Express, it's super easy to setup and use. You would be able to pass your data to your view in your Express router like this:
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!'});
});
And then use your JSON variables in your view, you can see the twig documentation here: Twig Doc
For example here, it would be {{ title }} or {{ message }} to use those variables. You can implement for loop, conditions and more using view engines.

What's the more efficient way to create dynamic tags on MeteorJS / Blaze?

I'm looking for a solution to manage a HTML tag type with a Reactive Var. I looked all the Blaze documentation but found nothing..
Simple example
I want to change a tag from div to form when a boolean ReactiveVar is updated.
Template.MyExample.onCreated(function() {
this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
getTag() {
return Template.instance().is_form.get() ? 'form' : 'div'
}
})
This obviously didn't work:
<Template name="MyExample">
<{{getTag}}>
</{{getTag}}>
</Template>
Nicer solution ?
The "best" way I found to get it was to create a tag template and list everycase a single time, but I didn't like that solution.
Template.MyExample.onCreated(function() {
this.is_form = new ReactiveVar(false)
})
Template.MyExample.helpers({
getTag() {
return Template.instance().is_form.get() ? 'form' : 'div'
}
})
Template.MyExample.events({
'click .switch'(e, instance) {
e.preventDefault()
instance.is_form.set(!instance.is_form.get())
}
})
Blaze Templates:
<Template name="MyExample">
<div>
Switch type
{{#MyTag tag=getTag}}
Parent tag is {{getTag}}
{{/MyTag}}
{{#MyTag tag="a" attributes=(object href="#" target="_blank")}}
Link
{{/MyTag}}
</div>
</Template>
<Template name="MyTag">
{{#if equals tag 'form'}}
<form {{attributes}}>
{{> Template.contentBlock }}
</form>
{{else if equals tag 'a'}}
<a {{attributes}}>
{{> Template.contentBlock }}
</a>
<!-- and more and more.... -->
{{else}}
<div {{attributes}}>
{{> Template.contentBlock }}
</div>
{{/if}}
</Template>
Helpers required:
Template.registerHelper('object', function({hash}) {
return hash;
})
Template.registerHelper('equals', function (a, b) {
return a === b
})
This is working but i'm wondering if it's to much for Meteor (and DOM updates). Does this solution works like an simple {{#if}}...{{/if}} or it's way heavier ?
The feature you request is basically not supported by Blaze. While static code generators can easily include dynamic tags, this is a very hard one at runtime where you have to deal with the DOM tree, whose element's tag-types are immutable by design.
I first thought of a workaround, that uses child swapping using jQuery in the onRendered of MyTag:
Template.MyTag.onRendered(function () {
const instance = this
instance.autorun(() => {
const data = Template.currentData()
const attributes = data.attributes || {}
const elementName = data.tag
const refTag = instance.$('.my-tag-ref')
const newTag = $(`<${elementName}>${refTag.html()}</${elementName}>`)
Object.keys(attributes).forEach(attKey => newTag.attr(attKey, attributes[ attKey ]))
newTag.addClass('my-tag-ref')
refTag.replaceWith(newTag)
})
})
But this is unfortunately not working, because the content bock looses it's reactivity and the jQuery instance of the current Template looses it's scope to the root element. I just add it here in case someone catches up on this and finds a solution that works.
Now there is still a solution that works using dynamic Templates:
<Template name="MyTag">
{{#Template.dynamic template=getTemplate data=getData}}
{{> Template.contentBlock }}
{{/Template.dynamic}}
</Template>
<template name="mytaga">
<a {{attributes}}>
{{> Template.contentBlock }}
</a>
</template>
<template name="mytagform">
<form {{attributes}}>
{{> Template.contentBlock }}
</form>
</template>
<template name="mytagdiv">
<div {{attributes}}>
{{> Template.contentBlock }}
</div>
</template>
As you can see the disadvantage is clearly that you have to define lots of new Templates. The advantage is, that you don't have to use so many if/else anymore and it pays out the more often you will have to include MyTag in your code.
The respective helpers look like the following:
Template.MyTag.helpers({
getTemplate() {
const instance = Template.instance()
console.log(instance.data)
return `mytag${instance.data.tag}`
},
getData () {
return Template.instance().data
}
})
This is working but i'm wondering if it's to much for Meteor (and DOM updates). Does this solution works like an simple {{#if}}...{{/if}} or it's way heavier ?
Blaze is overall slower than for example React or Vue. However, the rendering only updates if the reactive data updates, thus it is just as heavy as the amount of updates to be triggered.

How to include angular components in doc.fromhtml() jspdf?

I am trying to generate a pdf which includes angular components.
typescript:
let doc = new jsPDF();
let source = document.getElementById("content");
doc.fromHTML(
source,
15,
15,
{
'width': 180
});
doc.save("sample.pdf");
}
}
html:
<div id="content">
<sample-card *ngFor="let x of list; let i = index"
[selection] = list
<sample-card>
</div>
I am using Angular 4
doc.fromHTML() is working for simple 'div' like To be downloaded. But its not working for angular components. How to achieve this?
I did in this way ,
Passsing values in app html to the details, where it display those values in details html
In app.component.html
<div id="content" details [app1]="app" *ngFor="let app of applications">
In details.component.html
{{app1.labels}}
Here i'm waiting to get the data to be loaded[Tried with AfterViewChecked -- keeps on saving files and AfterViewInit is giving null (as it is executing only once)]
So waited for Random time say 5 sec[not good but its downloading the file]
setTimeout(()=>{
setTimeout(this.saveFile(), 1000*5);
},3000);
Here is the output i got[on left pdf and on right webpage with some extra content]
For the id on top div
<div id="content" >
Things to Learn
<div details [app1]="app" *ngFor="let app of applications">
</div>
Hari
</div>
Output is:
Method-2 :
Here i am using event emitter to tell parent when to save the file
when the child component receives the final item from the array of items [passed by parent to child] ,telling parent to save the file now [as i have received all of your items in the array]
Implemented with AfterViewInit where it emits true when length and count are same
On left html and on right ts [of parent]
on left ts and on right html [of child]
Output

How do I generate nested DOM elements based on an AJAX result in Angular?

I'm new to Angular so be gentle with me! I'm looking at rendering subsection DOM elements based on an AJAX response, how do I go about implementing the below in Angular?
On page load a list of section headers is returned from the controller:
Clicking on any of these sections (red) would show a subsection list (blue), each of these blue headers can be clicked to show another list (black), bearing in mind I only want to show the immediate-child sections for each section/subsection/sub-subsection header click:
I've got the template code I want to use for each of these, but how do I go about bringing these templates together?
So far from looking around I get the impression I should be creating a directive for the section, sub-section and sub-sub-section (yes?), can I then bind a template to the result of an HTTP Service call? I.e expanding as the detail screenshot above:
<div area="PSED">
Personal, Social and Emotional Development
<div aspect="MH">
Making Relationships
<div goal="BLAH">
<input type="checkbox"> Blah, Blah, Blah
</div>
</div>
</div>
I was hoping to reduce page load time by returning as little data as necessary and populating sections as-required by the user.
I hope this is a reasonable question as I couldn't find anything demonstrating what I need (perhaps my ignorance of ng was causing me to omit an important keyword from my searches).
Thanks in advance for any advice provided.
Andy
If I understand the question, you are trying to dynamically add nodes to a tree-like structure after an ajax call. You can use a combination of ng-include and a recursive template to do this. Here's a rough example that doesn't include the logic for collapsing nodes but I think it gets the idea across.
View:
<script type="text/ng-template" id="tree_item_renderer.html">
<span ng-click="add(data)">{{data.name}}</span>
<ul>
<li ng-repeat="data in data.nodes" ng-include="'tree_item_renderer.html'">
</li>
</ul>
</script>
<ul ng-app="Application" ng-controller="TreeController">
<li ng-repeat="data in tree" ng-include="'tree_item_renderer.html'"></li>
</ul>
Controller:
angular.module("myApp", []).
controller("TreeController", function($scope, $http) {
$scope.delete = function(data) {
data.nodes = [];
};
$scope.add = function(data) {
var post = data.nodes.length + 1;
var newName = data.name + '-' + post;
//make your call here and set your child node data
//$http.get('...').then(function(res){
// data.nodes.push({name: newName,nodes: res.data});
//});
//test data
data.nodes.push({name: newName,nodes: []});
};
$scope.tree = [{name: "Top Node", nodes: []}];
});
Working jsFiddle: http://jsfiddle.net/nfreeze/c9mrhxf2/1/

BackboneJS HandlebarsJS Display JSON from Spotify JSON

I want to display related artists on my Backbone View by using Spotifys API. So far so good, I managed to get the API/JSON data loaded, but I cant get it displayed in my Handlebars template yet, I get an empty HTML template and I dont know what I'm doing wrong?!?
Here is my Backbone Collection:
ArtistRelated.Collection = Backbone.Collection.extend({
url: function() {
return 'https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/related-artists';
},
parse: function(artists){
return artists;
}
});
And my Handlebars HTML:
{{#each this}}
<img src="{{images.url}}" alt="{{name}}">
<div>
<h3>{{name}}</h3>
</div>
{{/each}}
The API I took as an example:
https://api.spotify.com/v1/artists/1HY2Jd0NmPuamShAr6KMms/related-artists
What am I doing wrong?
Ok I solved it myself:
After adding/changing the parse method of the collection into:
parse: function(response){
return response.artists;
}
and the Handlebars template:
{{#each this}}
<img src="{{this.images.[0].url}}" alt="{{this.name}}">
<div>
<h3>{{this.name}}</h3>
</div>
{{/each}}
it now works! :-)