iterating over JSON object in ejs partial - javascript

I am trying to loop over each entry in "default", in my JSON file below, within an EJS partial.
{
"default": {
"1": {
"id": "alertmessages",
"title": "Your Messages",
"subtitle": "Tasks waiting for your attention",
"image": "alert.png",
},
"2": {
"id": "uploadr",
"title": "Upload",
"subtitle": "Upload",
"image": "baskets.png",
},
etc............
}
}
I am reading this JSON file into my node.js, parsing it and making it available for my dashboard view. as below
var jsondata = JSON.parse(require('fs').readFileSync('./app/routes/dashboard/buttons.json', 'utf8'));
var content = {
title: 'Dashboard',
user: req.user,
buttonsdata: jsondata
};
res.render('dashboard', content);
My dashboard view, includes an ejs partial in which I am trying to loop over all the objects contained within default (this number may vary). I want to do this without Jquery. But having trouble getting any of the suggestions working that I have found on other threads.
console.log("<%= buttonsdata.default.[1].id %>")
gives me what I would expect, however if i try and console log buttons.length, which is used in loop examples I have seen, it just comes up blank.
also how can I console log the entire contents of the object to see its structure?
thirdly - this object, in this manner as I can tell is available through ejs, however not to core javascript and i can only access it using the ejs <% %> tags. is this a correct understanding?

You can use Object.keys():
const buttonsdata = {
"default": {
"1": {
"id": "alertmessages",
"title": "Your Messages",
"subtitle": "Tasks waiting for your attention",
"image": "alert.png",
},
"2": {
"id": "uploadr",
"title": "Upload",
"subtitle": "Upload",
"image": "baskets.png",
}
}
};
Object.keys(buttonsdata.default).forEach(function (key) {
console.log(buttonsdata.default[key].id);
});
Now, according to your code, in the view should work like this:
<ul>
<% Object.keys(buttonsdata.default).forEach(function(key) { %>
<li><%= buttonsdata.default[key].id %></li>
<% }) %>
</ul>

Your json contains only objects, it doesn't have any arrays in it, so you won't be able to use buttonsdata.length
Displaying the whole object - display the object from within your controller, not your template. Look at this answer to see how
this object is available through ejs - yes, that's a correct understanding - I assume that by core javascript you mean the javascript that's executed in the browser. The whole ejs template is processed on the backend.

Related

Editing JSON files in NodeJS and DiscordJS

Right, so I am trying to wrap my head around editing (appending data) to a JSON file.
The file (users.json) looks like this:
{
"users": {
"id": "0123456789",
"name": "GeirAndersen"
}
}
Now I want to add users to this file, and retain the formatting, which is where I can't seem to get going. I have spent numerous hours now trying, reading, trying again... But no matter what, I can't get the result I want.
In my .js file, I get the data from the json file like this:
const fs = require('fs').promises;
let data = await fs.readFile('./test.json', 'utf-8');
let users = JSON.parse(data);
console.log(JSON.stringify(users.users, null, 2));
This console log shows the contents like it should:
{
"id": "0123456789",
"name": "GeirAndersen"
}
Just to test, I have defined a new user directly in the code, like this:
let newUser = {
"id": '852852852',
"name": 'GeirTrippleAlt'
};
console.log(JSON.stringify(newUser, null, 2));
This console log also shows the data like this:
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
All nice and good this far, BUT now I want to join this last one to users.users and I just can't figure out how to do this correctly. I have tried so many version and iterations, I can't remember them all.
Last tried:
users.users += newUser;
users.users = JSON.parse(JSON.stringify(users.users, null, 2));
console.log(JSON.parse(JSON.stringify(users.users, null, 2)));
console.log(users.users);
Both those console logs the same thing:
[object Object][object Object]
What I want to achieve is: I want to end up with:
{
"users": {
"id": "0123456789",
"name": "GeirAndersen"
},
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
}
When I get this far, I am going to write back to the .json file, but that part isn't an issue.
That's not really a valid data structure, as you're trying to add another object to an object without giving that value a key.
I think what you're really looking for is for 'users' to be an array of users.
{
"users": [
{
"id": "0123456789",
"name": "GeirAndersen"
},
{
"id": "852852852",
"name": "GeirTrippleAlt"
}
]
}
You can easily create an array in JS and the push() new items into your array. You JSON.stringify() that with no issue.
const myValue = {
users: []
};
const newUser = {
'id': '0123456789',
'name': "GeirAndersen'
};
myValue.users.push(newUser);
const strigified = JSON.stringify(myValue);

Pug - retrieving keys from a JSON object

I'm trying to create a single page website using Pug's templating engine and JSON as a database. Ultimately I'd like to store my different "pages" in the JSON file, and then render that JSON using different variables/mixins in my Pug template, but I keep receiving the errors, cannot read property "company" of undefined.
Any help would be greatly appreciated.
This is my Gulp task to build my Pug files, and pipe the JSON into the template:
// build the Pug files into HTML
gulp.task('build-pug', function buildHTML(){
var dataFile = 'source/javascript/pages.json';
return gulp.src('source/**/*.pug')
.pipe(data(function(file){
return JSON.parse(fs.readFileSync(dataFile));
}))
.pipe(pug({
pretty: true
}))
.pipe(gulp.dest('public'))
.pipe(browserSync.reload({
stream: true
}));
});
This is my pages.json file:
{
"pages": [
{
"year": "2016",
"company": "Abacus",
"home": "./assets/images/2016/home/abacus.png",
"home-url": "http://abacus.com",
"login": "./assets/images/2016/login/abacus.png",
"login-url": "http://abacus.com/login",
"pricing": "./assets/images/2016/pricing/abacus.png",
"pricing-url": "http://abacus.com/pricing"
},
{
"year": "2016",
"company": "Alfred",
"home": "./assets/images/2016/home/alfred.png",
"home-url": "http://alfred.com"
}
]
}
This is in my index.pug file where I'm trying to call keys from my JSON:
section.pricing
h1 Pricing Pages
div.content.pricing
each page in pages
p= page.pages.company
what about replacing your last line in index.pug with
p= page.company

Retrieving only the parent elements from firebase : Angularfire

The image shows the structure of my database.
I want to print 1, 2 ... (so on) i.e. the parent element names alone. But couldn't understand how to do that.
The Firebase Database is essentially one JSON object.
This object is in a tree structure. If you read from one location in the tree, you'll get each piece of data underneath it.
Take a look at this sample database.
{
"items": {
"1": {
"title": "Hi"
},
"2": {
"title": "Bye"
}
}
}
There is no way with the JavaScript SDK or AngularFire, to only read the parent keys of 1 and 2 under "items".
If you only want to read the parent keys, you'll need to create an index for them in the Firebase database.
{
"items": {
"1": {
"title": "Hi"
},
"2": {
"title": "Bye"
}
},
"itemKeys": {
"1": "Hi",
"2": "Bye"
}
}
Now you can create a reference at the itemKeys location and pass that to a $firebaseArray() or $firebaseObject().
var ref = new Firebase('<my-firebase-app>.firebaseio.com/itemKeys');
var syncArray = $firebaseArray(ref);
If you're concerned with keeping two separate data structures consistent, check out the client-side fan-out feature.
shallow=true
If you are using REST API add this to the end of your request url. Like this
https://docs-examples.firebaseio.com/rest/retrieving-data.json?shallow=true

Share generic logic and variable data across controllers

I have many controllers that operate within different pages of my application. I want to have alerts specific to each controller. An example for something pretty generic would be:
{
"saveSuccess": {
"alertClass": "success",
"header": "Success!",
"body": "File saved successfully.",
"buttons": [{
"label": "OK",
"tooltip": "close",
"fn": function () {
$scope.alertShown = false;
document.querySelector("#result").innerHTML = "success acknowledged";
}
}]
},
"confirmWarning": {
"alertClass": "warning",
"header": "Warning!",
"body": "This could cause a problem. Are you sure you want to proceed?",
"buttons": [{
"label": "OK",
"tooltip": "close",
"fn": function () {
$scope.alertShown = false;
document.querySelector("#result").innerHTML = "warning accepted";
}
}, {
"label": "CANCEL",
"tooltip": "close",
"fn": function () {
$scope.alertShown = false;
document.querySelector("#result").innerHTML = "warning canceled";
}
}]
},
"error": {
"alertClass": "critical",
"header": "Alert!",
"body": "The request cannot be processed. Please try again.",
"buttons": [{
"label": "OK",
"tooltip": "close",
"fn": function () {
$scope.alertShown = false;
document.querySelector("#result").innerHTML = "error acknowledged";
}
}]
}
}
But each page would have its own messages so this fairly generic data might get pretty length and pretty specific. I want to separate all this out into different files so I don't clutter all of my controllers with configuration objects like this. I could store it as stringified JSON and retrieve it using a service, then just repeat the fairly short logic that shows and hides the alert boxes between each controller, but stringifying functions seems kind of dumb and I feel there should be a fairly clean way to
a) make my template for the alert html a partial that can be rendered across the various views with something like <alert-html></alert-html>
b)somehow keep my model in a separate file that will be stored in each separate page's folder so there is a something like
-appPage1Dir
-appPage1View.html
-appPage1Controller.js
-appPage1AlertBoxModel.js
and I can put it into some var in appPage1Controller.js's scope
c)also pull in the show/hide logic into each page of the app.
I believe I could make a factory to return the data to my controller and pretty easily just inject the template into the view, but how can I elegantly also combine the show/hide logic so that's not repeated all over the place? I don't think that this is off-topic or opinion-based, I'm sure this is a common task in angular, but I'm just not familiar enough with it to know what to do.
JSBIN of the whole thing working in the controller.

How can I give an empty array to Handlebars/Mustache partial?

I have a problem with partials in Handlebars.js.
This is my template and a reuseable partial for it:
Handlebars.registerPartial("children", "{{#child}}[{{age}}]{{/child}}");
var children = Handlebars.compile("{{name}} -> {{>children}}");
And here is my first data:
children({
"name": "Alice",
"child": [{
"age": 6
}, {
"age": 11
}]
});
This leads to the expected and correct output:
Alice -> [6][11]
But when I use the following data with an empty array:
children({
"name": "Bob",
"child": []
});
With this data I will get the error message:
Error: You must pass a string or Handlebars AST to Handlebars.compile. You passed function (context, options) {if (!compiled) { compiled = compileInput(); } return compiled.call(this, context, options); }
But I expected the output "Bob ->"...
When I don't use the partial doing like this, everything works fine:
var children = Handlebars.compile("{{name}} -> {{#child}}[{{age}}]{{/child}}");
But I really want to do it with the partial due to reusability. Why can't I give an empty array to this partial?
Thanks!

Categories