Dynamic Links with Jade - node.js

Using Jade + Express + Node.js + Mongoose + MongoDB for my app, but this issue I ran into is likely in Jade:
I have some code as follows that prints a list of posts by title, author
div#articles
-each post in records
div.article
#{post.title} was written by #{post.author}
Link to Article
Now I want to the link in written Jade instead of HTML, but when I replace the line with
a(href='#{post.title}')
it links to /#{post.title} instead of the variable name such as /newpost1. Doing it as
a(href=#{post.title})
returns an error. I'm sure this is a syntax issue, but I can't find the solution in the GitHub documentation

pretty sure you can just do:
a(href=post.title)

jade:
- var records = [ { title: 'one', author: 'one' }, { title: 'two', author: 'two' } ];
div#articles
-each post in records
div.article
| #{post.title} was written by #{post.author}
a(href =post.title) Link to Article
html:
<div id="articles">
<div class="article">one was written by oneLink to Article</div>
<div class="article">two was written by twoLink to Article</div>
</div>

Related

Cannot access object properties in handlebars partial

I'm working on nodejs application. And want to display Mongoose result in web page. Template engine is express handlebars.
data= [
{name: 'some name', image: '/some_name.jpg', location: 'some location'},
{name: 'some name2', image: '/some_name2.jpg', location: 'some location2'},
{name: 'some name3', image: '/some_name3.jpg', location: 'some location3'}
]
I want to render data in handlebars partial. At first I'm iterating each object using #each and passing that object into the partial. Below is code how I'm doing.
{{#each data}}
{{> somePartial this}}
{{/each}}
In somePartial I want to access properties of the object.
<h5>Name: {{this.name}}</h5>
<h5>Image: {{this.image}}</h5>
<h5>Location: {{this.location}}</h5>
I can't see any value rendering in browser. In server console I get some warning or something like this Handlebars: Access has been denied to resolve the property 'xxxx' because it is not 'own property' of its parent..
Just use without this
{{> somePartial}}
...
<h5>Name: {{name}}</h5>
More info here: https://handlebarsjs.com/guide/partials.html#partial-parameters
To solve Handlebars: Access has been denied to resolve the property 'xxxx' because it is not 'own property' of its parent.
Map the result array in new array.
let result2 = result.map(val=>{
return {field1: val.field1,field2: val.field2, field3: val.field3 and so on}
})
For security reason handlebar does not allow to pass fetched result directly. You need to map with required field so that no sensitive data got passed.

How to label HTML for saving nested objects in Mongoose?

I have a model that looks like this:
const recipeSchema = new Schema({
title: { type: String , required: true},
description: { type: String , required: true},
steps:[{
text:{type:String},
ingredients:{type:String}
}]});
Using a bodyparser, I'm able to save data by simply tagging them in the name attribute of the HTML form. Like below:
<div class="input-field">
<textarea id="title" name="title" placeholder="Enter title here"></textarea>
<label for="title">Title</label>
</div>
This method works well for the first 2 fields (title and description), but I'm stuck on how to label them for the steps field. How would I make the code understand which input fields are for step.text and which are for steps.ingredient? And create an array of objects?
Figured it out. For anybody else who may stumble across this post, here's how you do it.
Basically you need to refer to the object in the array as (per the example above) in the following format:
step[0][text]
I couldn't find it anywhere in the documentation, but finally got it from this link:
http://www.thiscodeworks.com/how-to-save-input-from-html-form-to-json-file-using-body-parser-html-nodejs/5c44c4722178800014d5f127
How are you passing your data to the html page? I think using a view engine like EJS solves your problem better. It allows you to pass your data to a view, and then inject the data directly into your html elements.

Nested ListView or Nested Repeater

I am trying to created a nested repeater or a nested list view using WinJS 4.0, but I am unable to figure out how to bind the data source of the inner listview/repeater.
Here is a sample of what I am trying to do (note that the control could be Repeater, which I would prefer):
HTML:
<div id="myList" data-win-control="WinJS.UI.ListView">
<span data-win-bind="innerText: title"></span>
<div data-win-control="WinJS.UI.ListView">
<span data-win-bind="innerText: name"></span>
</div>
</div>
JS:
var myList = element.querySelector('#myList).winControl;
var myData = [
{
title: "line 1",
items: [
{name: "item 1.1"},
{name: "item 1.2"}
]
},
{
title: "line 2",
items: [
{name: "item 2.1"},
{name: "item 2.2"}
]
}
];
myList.data = new WinJS.Binding.List(myData);
When I try this, nothing renders for the inner list. I have attempted trying to use this answer Nested Repeaters Using Table Tags and this one WinJS: Nested ListViews but I still seem to have the same problem and was hoping it was a little less complicated (like KnockOut).
I know it is mentioned that WinJS doesn't support nested ListViews, but that seems to be a few years ago and I am hoping that is still not the issue.
Update
I was able to get the nested repeater to work correctly, thanks to Kraig's answer. Here is what my code looks like:
HTML:
<div id="myTemplate" data-win-control="WinJS.Binding.Template">
<div
<span>Bucket:</span><span data-win-bind="innerText: name"></span>
<span>Amount:</span><input type="text" data-win-bind="value: amount" />
<button class="removeBucket">X</button>
<div id="bucketItems" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#myTemplate')}"
data-win-bind="winControl.data: lineItems">
</div>
</div>
</div>
<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater"
data-win-options="{data: Data.buckets,template: select('#myTemplate')}">
</div>
JS: (after the "use strict" statement)
WinJS.Namespace.define("Data", {
buckets: new WinJS.Binding.List([
{
name: "A",
amount: 5,
lineItems: new WinJS.Binding.List( [
{ name: 'test item1', amount: 50 },
{ name: 'test item2', amount: 25 }
]
)
}
])
})
*Note that this answers part of my question, however, I would really like to do this all after a repo call and set the repeater data source programmatically. I am going to keep working towards that and if I get it I will post that as the accepted answer.
The HTML Repeater control sample for Windows 8.1 has an example in scenario 6 with a nested Repeater, and in this case the Repeater is created through a Template control. That's a good place to start. (I discuss this sample in Chapter 7 of Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition, starting on page 372, or 374 for the nested part.)
Should still work with WinJS 4, though I haven't tried it.
Ok, so I have to give much credit to Kraig because he got me on the correct path to getting this worked out and the referenced book Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition is amazing.
The original issue was a combination of not using templates correctly (using curly braces in the data-win-bind attribute), not structuring my HTML correctly and not setting the child lists as WinJS.Binding.List data source. Below is the final working code structure to created a nested repeater when binding the data from code only:
HTML:
This is the template for the child lists. It looks similar, but I plan on add more things so I wanted it separate instead of recursive as referenced in the book. Note that the inner div after the template control declaration was important for me.
<div id="bucketItemTemplate" data-win-control="WinJS.Binding.Template">
<div>
<span>Description:</span>
<span data-win-bind="innerText: description"></span>
<span>Amount:</span>
<input type="text" data-win-bind="value: amount" />
<button class="removeBucketItem">X</button>
</div>
</div>
This is the main repeater template for the lists. Note that the inner div after the template control declaration was important for me. Another key point was using the "winControl.data" property against the property name of the child lists.
<div id="bucketTemplate" data-win-control="WinJS.Binding.Template">
<div>
<span>Bucket:</span>
<span data-win-bind="innerText: bucket"></span>
<span>Amount:</span>
<input type="text" data-win-bind="value: amount" />
<button class="removeBucket">X</button>
<div id="bucketItems" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#bucketItemTemplate')}"
data-win-bind="winControl.data: lineItems">
</div>
</div>
</div>
This is the main control element for the nested repeater and it is pretty basic.
<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater"
data-win-options="{template: select('#bucketTemplate')}">
</div>
JavaScript:
The JavaScript came down to a few simple steps:
Getting the winControl
var bucketsControl = element.querySelector('#budgetBuckets').winControl;
Looping through the elements and making the child lists into Binding Lists - the data here is made up but could have easily came from the repo:
var bucketsData = selectedBudget.buckets;
for (var i = 0; i < bucketsData.length; i++) {
bucketsData[i].lineItems =
new WinJS.Binding.List([{ description: i, amount: i * 10 }]);
}
Then finally converting the entire data into a Binding list and setting it to the "data" property of the winControl.
bucketsControl.data = new WinJS.Binding.List(bucketsData);
*Note that this is the entire JavaScript file, for clarity.
(function () {
"use strict";
var nav = WinJS.Navigation;
WinJS.UI.Pages.define("/pages/budget/budget.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
var bindableBuckets;
require(['repository'], function (repo) {
//we can setup our save button here
var appBar = document.getElementById('appBarBudget').winControl;
appBar.getCommandById('cmdSave').addEventListener('click', function () {
//do save work
}, false);
repo.getBudgets(nav.state.budgetSelectedIndex).done(function (selectedBudget) {
var budgetContainer = element.querySelector('#budgetContainer');
WinJS.Binding.processAll(budgetContainer, selectedBudget);
var bucketsControl = element.querySelector('#budgetBuckets').winControl;
var bucketsData = selectedBudget.buckets;
for (var i = 0; i < bucketsData.length; i++)
{
bucketsData[i].lineItems = new WinJS.Binding.List([{ description: i, amount: i * 10 }]);
}
bucketsControl.data = new WinJS.Binding.List(bucketsData);
});
});
WinJS.UI.processAll();
}
});
})();

is this node.js mustache partials functionality ideal?

I'm new to node and have been trying to find a way to integrate mustache in a way thats flexible for how I build templates. After trying hogan, mustache-express and the other permutations of mustache, I found the following to make sense to me.
Im not sure if there is a more efficient way of handling this. Basically I like to have control of partial templates so I can load them in module positions on a master template. So this is the basic setup
I have 3 partial templates and one wrapper/master template, the following values are just for example.
./views/wrapper.tpl
<html>
<title>{{ title }}</title>
<body>
<h1>{{ heading }}</h1>
<div>{{> position_1 }}</div>
<div>{{> position_2 }}</div>
<div>{{> position_3 }}</div>
</body>
</html>
./views/module_1.tpl
<h2>{{module_1.title}}</h2>
<p>{{module_1.body}}</p>
./views/module_2.tpl
<h2>{{module_2.title}}</h2>
<p>{{module_2.body}}</p>
./views/module_3.tpl
<h2>{{module_3.title}}</h2>
<p>{{module_3.body}}</p>
Im using Express but removed the default jade render engine. I only included the code that needs to be added to a default express install.
mustache and fs are needed
.
.
.
var mustache = require('mustache');
var fs = require('fs');
.
.
.
app.get('/', function(req, res){
// grab master template
var wrapper = fs.readFileSync('./views/wrapper.tpl', "utf8");
// load data that will be used in template & partials
var data = {
'title': 'dashboard',
'heading': 'welcome to your dashboard',
'module_1':{
'title': 'module 1 title',
'body': 'module 1 body'},
'module_2':{
'title': 'module 2 title',
'body': 'module 2 body'},
'module_3':{
'title': 'module 3 title',
'body': 'module 3 body'}};
// load partial templates
var partials = {'position_1': fs.readFileSync('./views/module_1.tpl', "utf8"),
'position_2': fs.readFileSync('./views/module_2.tpl', "utf8"),
'position_3': fs.readFileSync('./views/module_3.tpl', "utf8")}
// include partials and then replace variables with given data
var html = mustache.to_html(wrapper, data, partials);
// send output to browser
res.send(html);
});
.
.
.
.
This to me makes alot more sense then other examples I have seen, and it works well with mustache. I am able to give the user custom control as to where they want the modules to be positioned. So my questions are
Is there a more efficient way of doing this?
Is there anything wrong with the way Im going about this?
By bypassing Express rendering capabilities what am I missing out?
Why should I use libraries like consolidate and add another layer to express?
Thanks!
If you don't want express rendering, thats fine in my book, I even removed the whole module in some of my lab projects just to get a better understanding of routing in node.
However I'd really advice against using readFileSync since It's a blocking method and will make concurency a problem, always use readFile so you get that async callback.

Mustache section in Couchdb issues

I am a couchdb newbie running CouchDB 1.0.1.
I have a very basic issue. I cannot get Mustache Sections to render in a list.
Here is my list with the data hard coded from an example.
function(head, req) {
start({
"headers": {
"Content-Type": "text/html"
}
});
var mustache = require("lib/mustache");
var view = {name: "Joe's shopping card",items: ["bananas", "apples"]};
var template = "{{name}}: <ul> {{#items}}<li>{{.}}</li>{{/items}} </ul>";
return mustache.to_html(template,view);
Outputs:
Joe's shopping card: <ul> <li></li><li></li></ul>
Please help!!!
Thank you,
/ Jeff
Oh barf, I just figured it out and it is a little rediculous. Here it is for anyone else who wants to save some time. Add this to your template "{{%IMPLICIT-ITERATOR}}".
So:
var template = "{{name}}: <ul> {{#items}}<li>{{.}}</li>{{/items}} </ul>";
Becomes:
var template = "{{%IMPLICIT-ITERATOR}}{{name}}: <ul> {{#items}}<li>{{.}}</li>{{/items}} </ul>";

Resources