Handlebars:How do i access array by value? - handlebars.js

I have a simple array 'names' with name and id.
I'd like to access the name from other loop (phones).
Code is below:
{{#names}}
{{name}} - {{id}} // this shows for example '123456 - 001'
{{/names}}
{{#phones}}
{{number}} - {{id}}
-->here i'd like to fetch a 'name' from names based on phone {{id}}
{{/phones}}
Is there something like {{../names.id['001']}}??
Is this possible?

I'm doing something like this:
{{#phones}}
{{#../names}}
{{#ifeq ../id this.id}}
{{this.name}}
{{/ifeq}}
{{/../names}}
{{/phones}}
with ifeq being this helper:
Handlebars.registerHelper('ifeq', function (a, b, options) {
if (a == b) { return options.fn(this); }
});

Related

How to extract span text value in this case for CSS selector?

<p>
<span class="name">type:</span> phone
<span class="name">comment</span>
: there are 103002 units
</p>
I want to extract the values of 'phone' and 'there are 103002'. I can get the type and comment:
response.css('p span.name').getall()
But how to extract 'phone' and 'there are 103002 units' with the corresponding keys (type & comment)?
You can get it by xPath:
response.selector.xpath('//p/text()').getall()
or this:
response.css('p::text').getall()
Check more in here: https://docs.scrapy.org/en/latest/topics/selectors.html#constructing-selectors
With BeautifulSoup, you can use the .next_sibling method
from bs4 import BeautifulSoup
html = """
<p>
<span class="name">type:</span> phone
<span class="name">comment</span>: there are 103002 units
</p>"""
soup = BeautifulSoup(html, "html.parser")
for tag in soup.find_all("span", class_="name"):
print(tag.text, tag.next_sibling.strip())
Output:
type: phone
comment : there are 103002 units
I found the following reduce, call function on this site: get element’s text content without its child nodes, paired with other logic to get the key and values into an array matched as key/value pairs. I recommend reading the article in full as it explains all the steps for getting the textNodes using reduce and call methods in full detail. The method runs over the nodeList and checks the childs nodeType, this builds the textContent by adding matches to the result.
We can check nodeType: Node.ELEMENT_NODE => value === 1 for the keys... Example: An Element node like <p> or <div>.
Then we check nodeType: Node.TEXT_NODE => value === 3 for the text... Example: The actual Text inside an Element or Attr.
See the following article on MDN: nodeType
We add the return value to a variable. Optionally, you can split the string at the colon to separate the results, then trim the results to get the text content.
To pair the key and value we create an object, then iterate over the keys or value split() array with a for loop using an incrementor and arr.length, add the key/value pairs to the object. A for of loop to get the key/value pairs.
const parentElement = document.querySelector('p');
const keyValuePairs = (el) => {
let text = [].reduce.call(el.childNodes, (a, b) => {
return a + (b.nodeType === 3 ? b.textContent : '');
}, '');
let keys = [].reduce.call(el.childNodes, (a, b) => {
return a + (b.nodeType === 1 ? b.textContent : '');
}, '');
let arrValues = text.split(':');
let arrKeys = keys.split(':');
let obj = {};
// Using loop to insert key/value pairs into the Object
for (let i = 0; i < keys.length - 1; i++) {
obj[arrKeys[i]] = arrValues[i];
}
return obj;
}
// Iterate over the object and get the key/value pairs
for (let key of Object.keys(keyValuePairs(parentElement))) {
if (keyValuePairs(parentElement)[key] !== undefined) {
console.log(`${key.trim()} => ${keyValuePairs(parentElement)[key].trim()}`);
}
}
<p>
<span class="name">type:</span> phone
<span class="name">comment</span>: there are 103002 units
</p>

How to access final element in Handlebars.js array?

Given the following data structure:
{
"name" : "test",
"assetType" : "Home",
"value" : [
{
"value" : "999",
"date" : "10/03/2018"
},
{
"value" : "1234.56",
"date" : "10/04/2018"
}
]
}
How can I directly access the first and last element of value in Handlebars? My code is:
<td>{{value.[0].value}}</td>
<td>{{value.[value.length - 1].value}}</td>
The first statement works fine, but I cannot figure out how to access the last element. value.length inside the []'s does not return any value, but rendering value.length outside of the array works fine.
I tried using #first and #last in the array but those don't seem to work either.
As already pointed out, you can easily solve this with a template helper:
Template.myTemplate.helpers({
first (arr) {
return arr && arr[0]
},
last (arr) {
return arr && arr[arr.length - 1]
},
atIndex (arr, index) {
return arr && index >= 0 && index <= arr.length - 1 && arr[index]
}
})
You can then create a context using #with where the context object is the result of the helpers. Inside this context you can access properties using this.
Accessing values with the name value would look like the following:
<td>{{#with first value}}{{this.value}}{{/with}}</td>
<td>{{#with last value}}{{this.value}}{{/with}}</td>
<td>{{#with atIndex value 5}}{{this.value}}{{/with}}</td>

Converting FirebaseDataSnapshot into a JS object

I am pushing on object into my ROOMS array with .on("child_added", ....) as below. One of the parts of that object is an array of other objects (Player obj which has some properties like id, name, and so on). How do i assign to ROOMS.players because snap.child("players").val() does not work (EXCEPTION: Error trying to diff '[object Object]') snap.child("players").val() structure looks something like this:
-rooms
-id
-name
-isRoomFull
+board
-players
-kEFvdfeff84fdfdff
-id
-name
-kEFvd4545dfjh9fvv
-id
-name
getRooms() {
this.roomsRef.on("child_added", function(snap) {
ROOMS.push({
id: snap.child("id").val(),
name: snap.child("name").val(),
players: [], //how to assign to this property
isRoomFull: snap.child("isRoomFull").val(),
board: snap.child("board").val(),
})
});
I would try something like that:
var obj = snap.child("players").val().players;
var players = Object.keys(obj).map(key => return obj[key]);
ROOMS.push({
id: snap.child("id").val(),
name: snap.child("name").val(),
players: players,
isRoomFull: snap.child("isRoomFull").val(),
board: snap.child("board").val(),
});
See this question for more details:
Converting a JS object to an array

How to get final iteration number in Meteor

In Meteor we have the '#index' operator to get the index value of the iteration. But I wanted to get the total number of iterations then print that number on the page. So the page at top might read the total number of boys in a group.
For example, I might have something like:
Total = {{#each StudentMale}} {{formatMaleCount #index}} {{/each}}
and a register helper just to add 1 to the number
Template.registerHelper('formatMaleCount', function (count) {
return count + 1;
});
and this would print:
Total = 1234567
I'd like to have:
Total = 7
Coming up short on how to do this. I tried to have the helper put the values in an array, but this wouldn't work since a new array is produced on each iteration.
StudentMale is presumably an array or cursor, so in a new helper:
If it's an array:
arrayLength( array ) {
return array.length;
}
Or if it's a collection:
studentMaleLength() {
return StudentMales.find().fetch().length;
}
Then just call your helper.

Possible to do operations within Handlebars expressions?

Say that I want to add a dollar sign to a Handlebars output:
${{price}}
When price actually evaluates into a number, the final output looks good: $100
But when price hasn't been defined yet, the output is just a lonely dollar sign $ which looks odd just sitting by itself on the page.
I can define the Handlebars helper to include the dollar sign:
Handlebars.registerHelper('priceWithDollarSign', function() {
return( "$" + totalPrice );
});
But then I need to define a second helper to display it without a dollar sign:
Handlebars.registerHelper('priceWithoutDollarSign', function() {
return totalPrice;
});
Would it be possible to just do it inside the Handlebars expression itself?
{{"$" + price}} for when I want the dollar sign.
{{price}} for when I don't want the dollar sign.
In this way, when price hasn't been defined the output is just blank and doesn't look odd on the page.
I figured out how to do it for this dollar sign case. I guess I can extrapolate this out to other similar situations.
Handlebars.registerHelper("formatToCurrency", function(number, plain) {
if (number && plain) {
return number; //return the plain number
} else if (number && plain == null ) {
return ("$" + number); //return the number with $ sign
} else {
return null; //return nothing
}
});
If I do
{{formatToCurrency price null}}
I get 100
If I do
{{formatToCurrency price}}
I get $100
If price is undefined, it is just blank.

Resources