Handlebars: How to make custom helper for sum array? - handlebars.js

I try like this:
sum: function(arr) {
const s = 0;
for(const i=0; i<arr.length; i++) {
s = s + arr[i];
}
return s;
}
and output that in table like this:
{{#each something}}
<td>{{sum this}}</td>
{{/each}}
but in this case nothing appears, any suggestions?
[this] array contains numbers
50 | 10 | 10 | 10 | 5 | 5 |
60 | 10 | 10 | 10 | 5 | 5 |
50 | 10 | 10 | 10 | 10 | 10|
so result should be
160 | 30 | 30 | 30 | 20 | 20 |
but in my method return zero values.
If I do as #Christophe Thiry show me:
sum: function(item) {
result = item[0]
for (i=0; i<result.length; i++) {
for (j=1; j<item.length; j++) {
result[i] = result[i]+item[j][i];
}
}
return result.toString();
}
and just:
<td>{{sum this}}</td>
I get TypeError: Cannot read property 'length' of undefined
Schema model:
const StateResultSchema = new Schema({
electoralUnit: {
type: Schema.Types.ObjectId,
ref: 'ElectoralUnit',
required: true,
unique: true
},
allVotes: {
type: Number,
required: true
},
validVotes: {
type: Number,
required: true
},
invalidVotes: {
type: Number,
required: true
},
partyVotes: {
type: [Number],
required: true
}
});
this is how it look like in MongoDB Compass"
_id:ObjectId("5ac4e01d46fa2b21280bd981")
electoralUnit:ObjectId("5ab906612f30fe23dc592591")
allVotes:100
validVotes:90
invalidVotes:10
partyVotes:[50,10,10,10,5,5]
__v:0

You don't need the each helper, you have to use the helper that you've created directly so {{sum something}} and also review your sum helper because you iterate only over one array.
Look at the below snippet to see how to achieve that.
$(document).ready(function () {
var context = { "something" : [
{ "_id":"5ac4e01d46fa2b21280bd981", "electoralUnit":"5ab906612f30fe23dc592591", "allVotes":100, "validVotes":90, "invalidVotes":10, "partyVotes":[50,10,10,10,5,5], "__v":0},
{ "_id":"5ac4e01d46fa2b21280bd982", "electoralUnit":"5ab906612f30fe23dc592592", "allVotes":100, "validVotes":90, "invalidVotes":10, "partyVotes":[50,10,10,10,5,5], "__v":0},
{ "_id":"5ac4e01d46fa2b21280bd983", "electoralUnit":"5ab906612f30fe23dc592593", "allVotes":100, "validVotes":90, "invalidVotes":10, "partyVotes":[60,10,10,10,5,5 ], "__v":0},
{ "_id":"5ac4e01d46fa2b21280bd984", "electoralUnit":"5ab906612f30fe23dc592594", "allVotes":100, "validVotes":90, "invalidVotes":10, "partyVotes":[50,10,10,10,10,10], "__v":0}
]
};
Handlebars.registerHelper('sum', function(item) {
result = item[0].partyVotes;
for (i=0; i<result.length; i++) {
for (j=1; j<item.length; j++) {
result[i] = result[i]+item[j].partyVotes[i];
}
}
return result.toString();
});
var source = $("#sourceTemplate").html();
var template = Handlebars.compile(source);
var html = template(context);
$("#resultPlaceholder").html(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="sourceTemplate" type="text/x-handlebars-template">
{{sum something}}
</script>
<br/>
<div id="resultPlaceholder">
</div>

Related

Cypress - I need to verify that the result of the function is the same as the value of the slug element

it.only('Create new film', () => {
function randomStringFc() {
var a = "abcdefghijklmnopqrstuvwxyz";
var n = "1234567890";
var t = function(input, length) { return Array(length).fill(input).map(function(v) { return v[Math.floor(Math.random() * v.length)] }).join(''); }
var m = "testFilm-" + t(a+n, 8);
return m;
}
cy.contains('Create new', { timeout: 12000 }).click()
cy.get('#title', { timeout: 12000 }).then( input => {
let filmName = cy.wrap(input).type(randomStringFc())
cy.get('#slug').should('have.value', filmName)
})
})
Timed out retrying after 10000ms: expected '<input#slug.form-control>' to have value { Object (userInvocationStack, specWindow, ...) }, but the value was 'testfilm-fruh5tn5'
This is not how you work with chains. There's no meaningful return value.
You need to use another variable to do what you want:
cy
.get('#title', { timeout: 12000 })
.then(input => {
const randomString = randomStringFc();
cy
.wrap(input)
.type(randomString);
cy
.get('#slug')
.should('have.value', randomString);
});

Storing dynamically QML objects

i want to store in a variant or a list, a set of dynamically QML created objects.
when i do it once, it works nice:
property var obj
var component = Qt.createComponent("MyObject.qml")
obj = componente.createObject(contenedor)
i am trying to iterate 10 times to create a 10 length object
property variant objs
var component = Qt.createComponent("MyObject.qml")
for (var i=0; i<10; i++){
objs[i] = component.createObject(contenedor)
}
How can i do it?
Edit: i attach you my 2 files: main.qml and MyObject.qml
main.qml
import QtQuick 2.1
import QtQuick.Window 2.1
Rectangle {
visible: true
width: 1920
height: 1080
color: "white"
id: contenedor
property variant colors: ['blue', 'red', 'gray', 'orange']
property var arrayObjects: []
property int currentObj: 0
property var singleObject
Component.onCompleted: init()
function init(){
var componente = Qt.createComponent("MyObject.qml")
//singleObject = componente.createObject(contenedor,{"x":50,"y":10})
//singleObject = componente.createObject(contenedor)
for (var i=0; i<colors.length; i++){
arrayObjects.push(componente.createObject(contenedor))
}
for (var i=0; i<colors.length; i++){
console.log(arrayObjects[i])
}
next()
}
function next(){
console.log("Next");
if(currentObj > colors.length){
currentObj--
}else if(currentObj===colors.length){
console.log('--------------------Reset')
currentObj = 0
}
console.log("Index: " + currentObj)
arrayObjects[currentObj].visible = true
arrayObjects[currentObj].color = colors[currentObj]
arrayObjects[currentObj].end.connect(next)
arrayObjects[currentObj].init()
/*singleObject.visible = true
singleObject.color = colors[currentObj]
singleObject.end.connect(next)
singleObject.init()*/
currentObj++
}
}
MyObject.qml
import QtQuick 2.1
Rectangle {
visible: true
anchors.fill: parent
id: object
signal end()
Timer {
id: timer
running: false
repeat: false
onTriggered: end()
}
function init(){
console.log('Init object')
timer.interval = 5000
timer.start()
}
}
Something like this should work:
property var objs : []
var component = Qt.createComponent("MyObject.qml")
for (var i=0; i<10; i++){
objs.push(component.createObject(contenedor))
}
for (var i=0; i<10; i++){
console.log(objs[i])
}
Edit after your added code:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQml.Models 2.2
Window {
visible: true
width: 920
height: 500
color: "white"
id: contenedor
property variant colors: ['blue', 'red', 'gray', 'orange']
property var arrayObjects: []
property int currentObj: 0
property int zIndex: 1
property var singleObject
Component.onCompleted: init()
function init(){
var componente = Qt.createComponent("MyObject.qml")
//singleObject = componente.createObject(contenedor,{"x":50,"y":10})
//singleObject = componente.createObject(contenedor)
for (var i=0; i<colors.length; i++){
arrayObjects.push(componente.createObject(contenedor))
}
for (var i=0; i<colors.length; i++){
console.log(arrayObjects[i])
}
next()
}
function next(){
console.log("Next");
if(currentObj > colors.length){
currentObj--
}else if(currentObj===colors.length){
console.log('--------------------Reset')
currentObj = 0
}
console.log("Index: " + currentObj)
arrayObjects[currentObj].visible = true
console.log("Color: " + colors[currentObj]);
arrayObjects[currentObj].color = colors[currentObj];
arrayObjects[currentObj].z = zIndex;
arrayObjects[currentObj].end.connect(next)
zIndex++;
arrayObjects[currentObj].init()
/*singleObject.visible = true
singleObject.color = colors[currentObj]
singleObject.end.connect(next)
singleObject.init()*/
currentObj++
}
}

Read array Objects from Firebase + Firepad + Ace Editor

I am storing the data to the Firebase when the user starts typing in the ACE editor with the help of firepad.
The data is stored in the Firebase like an Array. Each character in array index.
I just typed "Hi Its" then "Hi Its Nithi" then inserted "Hi Its Me Nithi"
It's really hard to read the data with key, value, array, index with -ve value.
Is there any plugin to convert handle the index?
Data:
B11
o
0: 7
1: -1
B12
o
0: 7
1: "N"
B13
o
0: 8
1: "ithi"
B14
o
0: 7
1: "M"
2: 5
B15
o
0: 8
1: "e"
2: 5
Am really tired by constructing a code like :
Which grow and getting more complex.
codeTimeFirebaseRef.on('value', function(snapshot) {
var data = snapshot.val();
var i = 1;
var jsonData = {};
var jsonDataArray = {};
async.forEach(Object.keys(data), function(key) {
var code = data[key];
if (code.o.length === 1) {
if (jsonDataArray.length > 1) {
jsonData.answer = jsonDataArray;
codes.push(jsonData);
i++;
jsonData = {};
jsonDataArray = {};
} else {
jsonData.index = i;
jsonData.time = code.t;
if (typeof code.o[0] === 'string') {
jsonDataArray = code.o[0];
} else if (typeof code.o[0] === 'number') {
jsonDataArray = jsonDataArray.substring(0, code.o[0]);
}
}
} else {
if (typeof code.o[1] === 'string') {
jsonDataArray += '' + code.o[1];
} else if (typeof code.o[1] === 'number') {
jsonDataArray = jsonDataArray.substring(code.o[0], code.o[1]);
}
}
Please help to get through.

Issue creating Stacked Column Chart

I am trying to create a stacked column chart from the following data.
PrimaryAdvisorName AccountTypeName TotalCustodianValue
Paul T1 100
John T2 200
John T3 300
but the issue I am facing is all the series gets stacked on the same x-axis label.I don't see other x-axis values
|
|
| | |
| | |
| | |
-------------
Paul
foreach (ProfileLineItem x in data.LineItems)
{
Series s = new Series
{
Name = x.AccountTypeName,
ChartType = SeriesChartType.StackedColumn,
Font = new Font("Segoe UI", 8),
CustomProperties = "DrawingStyle=Cylinder",
Legend = "Default",
ChartArea="Default"
};
string xVal = x.PrimaryAdvisorName;
bool found = false;
foreach (Series t in stackedColumnChart.Series)
{
foreach (DataPoint dt in t.Points)
{
if (xVal == dt.AxisLabel)
{
found = true;
break;
}
}
if(found)
{
var y2 = data.LineItems.Where(i => (i.PrimaryAdvisorName.Equals(xVal) && i.AccountTypeName.Equals(x.AccountTypeName)))
.Select(k => k.TotalCustodianValue);
foreach (double d in y2)
{
s.Points.AddXY(xVal, d);
}
break;
}
}
if (!found)
{
var y2 = data.LineItems.Where(i => (i.PrimaryAdvisorName.Equals(xVal) && i.AccountTypeName.Equals(x.AccountTypeName)))
.Select(k => k.TotalCustodianValue);
foreach (double d in y2)
{
s.Points.AddXY(xVal, d);
}
}
stackedColumnChart.Series.Add(s);
}

Flex sort Datagrid with custom compareFunction (sort numbers numerical and text alphanumerical)

I need following result.
All numbers use numeric sorting and all strings use alphanumeric sort. Further more , the numeric values should be listed before the string values:
Example:
before "i","9","89","0045","b","x"
after "9","0045","89","b","i","x"
My current code looks like this: (numeric sort works but my strings are distributed to the top and bottom?! -> "b","x","9","0045","89","i")
public function compareFunction(obj1:Object, obj2:Object):int {
var id1:String = (obj1 as WdProblem).id;
var id2:String = (obj2 as WdProblem).id;
if(id1.replace(' ', '') == "n") {
var sdld:int = 0;
}
var num1:int = Number(id1);
var num2:int = Number(id2);
if(stringIsAValidNumber(id1) && stringIsAValidNumber(id2)) {
if(num1 == num2) {
return 0;
} else {
if(num1 > num2) {
return 1;
} else {
return -1;
}
}
} else if(!stringIsAValidNumber(id1) && !stringIsAValidNumber(id2)) {
return ObjectUtil.compare(id1, id2);
//return compareString(id1, id2);
} else if(!stringIsAValidNumber(id1) && stringIsAValidNumber(id2)) {
return 1;
} else if(stringIsAValidNumber(id1) && !stringIsAValidNumber(id2)) {
return -1;
}
return -1;
}
private function stringIsAValidNumber(s:String):Boolean {
return Boolean(s.match("[0-9]+(\.[0-9][0-9]?)?"));
}
My suggestion is to break it down into it's constituent parts especially if you have a scenario like this with 1 or more priority sorts. The key is to move onto the next sort only when the first sort returns they are equal.
For your case, I would build 2 sorts, one for numeric and the other for alpha-numeric, then your main sort can prioritize these by calling the sub-sort.
For example I have something similar:
private function sort2DimensionsByIncomeVsTime(a:OLAPSummaryCategory, b:OLAPSummaryCategory, fields:Array = null):int
{
var sort:OLAPSort = new OLAPSort();
var incomeSort:int = sort.sortIncome(a, b);
var nameSort:int = sort.sortName(a, b);
var yrSort:int = sort.sortYear(a, b);
var moSort:int = sort.sortMonth(a, b);
if (incomeSort == 0)
{
if (nameSort == 0)
{
if (yrSort == 0)
{
//trace(a.name, a.year, a.month, 'vs:', b.name, b.year, b.month, 'month sort:', moSort);
return moSort;
}
else return yrSort;
}
else return nameSort;
}
else return incomeSort;
}
I use following sort function for AlphaNumeric sorting:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
creationComplete="onCC()"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.utils.ObjectUtil;
import mx.utils.StringUtil;
import spark.collections.Sort;
import spark.collections.SortField;
public function onCC():void
{
var acAlphaNumericString:ArrayCollection = new ArrayCollection();
acAlphaNumericString.addItem({ name: "NUM10071" });
acAlphaNumericString.addItem({ name: "NUM9999" });
acAlphaNumericString.addItem({ name: "9997" });
acAlphaNumericString.addItem({ name: "9998" });
acAlphaNumericString.addItem({ name: "9996" });
acAlphaNumericString.addItem({ name: "9996F" });
acAlphaNumericString.addItem({ name: "i" });
acAlphaNumericString.addItem({ name: "9" });
acAlphaNumericString.addItem({ name: "89" });
acAlphaNumericString.addItem({ name: "0045" });
acAlphaNumericString.addItem({ name: "b" });
acAlphaNumericString.addItem({ name: "x" });
var sf:SortField = new SortField("name");
sf.compareFunction = function(o1:Object, o2:Object):int
{
return compare(o1.name, o2.name);
}
var sort:Sort = new Sort();
sort.fields = [ sf ];
acAlphaNumericString.sort = sort;
acAlphaNumericString.refresh();
for each (var o:Object in acAlphaNumericString)
trace(o.name);
}
public static function compare(firstString:String, secondString:String):int
{
if (secondString == null || firstString == null)
return 0;
var lengthFirstStr:int = firstString.length;
var lengthSecondStr:int = secondString.length;
var index1:int = 0;
var index2:int = 0;
while (index1 < lengthFirstStr && index2 < lengthSecondStr)
{
var ch1:String = firstString.charAt(index1);
var ch2:String = secondString.charAt(index2);
var space1:String = "";
var space2:String = "";
do
{
space1 += ch1;
index1++;
if (index1 < lengthFirstStr)
ch1 = firstString.charAt(index1);
else
break;
} while (isDigit(ch1) == isDigit(space1.charAt(0)));
do
{
space2 += ch2;
index2++;
if (index2 < lengthSecondStr)
ch2 = secondString.charAt(index2);
else
break;
} while (isDigit(ch2) == isDigit(space2.charAt(0)));
var str1:String = new String(space1);
var str2:String = new String(space2);
var result:int;
if (isDigit(space1.charAt(0)) && isDigit(space2.charAt(0)))
{
var firstNumberToCompare:int = parseInt(StringUtil.trim(str1));
var secondNumberToCompare:int = parseInt(StringUtil.trim(str2));
result = ObjectUtil.numericCompare(firstNumberToCompare, secondNumberToCompare);
}
else
result = ObjectUtil.compare(str1, str2);
if (result != 0)
return result;
}
return lengthFirstStr - lengthSecondStr;
function isDigit(ch:String):Boolean
{
var code:int = ch.charCodeAt(0);
return code >= 48 && code <= 57;
}
}
]]>
</fx:Script>
</s:Application>

Resources