Dojo lang.replace - how to provide default value, instead of 'undefined'? - javascript

Dojo lang.replace() replaces the undefined placeholders with undefined text. Is it possible to define the default value within placeholder?
Let's say I want to have the following placeholder:
<div class="message">The query returned {result.rows:0} rows</div>
The placeholder will be replaced with the numbers of rows returned, but when the variable rows is not available (for exapmle, the result contains error message) it will be replaced with 0.

There are two approaches you can consider. The first is to mixin the results object with defaults before passing it into the replace function.
var defaults = {
rows: 0
};
var data = lang.mixin(lang.clone(defaults), result);
lang.replace(template, data);
The second approach is instead of passing a data object, pass a function that knows how to default the value when missing.
http://dojotoolkit.org/reference-guide/1.9/dojo/_base/lang.html#with-a-function

Related

Javascript JSON.stringify replacer return value problem?

I tried to write some javascript code that multiplies with number salaries of each person, and makes them into string with JSON.stringify.
For example, in salaries, the name and the original salary are in here like this:
let salaries = {
james:100000,
john:200000,
jane:300000
};
and I want to express like this: {james:110000,john:220000,jane:330000}
So, I wrote the code like...
let payjson = JSON.stringify(pays, function replacer(key, value){
return value*1.1;
}); // 1st try
and got an error, the values are changed like [object Object], NaN.
However, this code just worked for me
let payjson = JSON.stringify(pays, function replacer(key, value){
return Number.isInteger(value)? Math.floor(value*1.1): value;
}); // 2nd try
I wonder why the first one didn't work the way I wanted and the second just worked the way I wanted to.
As the stringify() function documentation clearly explain, the replacer function is initially passed the object, and then each of the properties. So, you are seeing this behavior. The first time when the value comes in as object type, and the multiplication is attempted, it crashes and does not subsequently pass the properties, so the overall return of the stringify() is null. In your 2nd try code, you are checking the value and only if it is of numeric type, you are doing the math and returning a calculated value, which is used by stringify() to append to the output string.
See the documentation, and mainly this paragraph :
Initially, the replacer function is called with an empty string as key representing the object being stringified. It is then called for each property on the object or array being stringified.
It looks like you want to create a copy of the original object with 10% higher salaries:
const salaries = {
james:100000,
john:200000,
jane:300000
};
const res=Object.fromEntries(Object.entries(salaries).map(([k,v])=>[k,1.1*v]));
console.log(res);
// this can be strigified too:
console.log(JSON.stringify(res));
// and the input object is unchanged:
console.log(salaries);
When the replacer function is first called, key is assigned an empty string. However, the function is still expected to return value, otherwise it terminates.
let salaries = {
james:100000,
john:200000,
jane:300000
};
document.write(JSON.stringify(salaries,(k,v)=>{return k==''?v:Math.floor(v*1.1);}));

Function returns [object Set] instead of an actual Set

I have a function
function recursiveDivisionWrap(width, height, colStart, colEnd, rowStart, rowEnd)
in which i have an empty set
let blockedNodes = new Set();
inside this function I have another, recursive function
function recursiveDivision(width, height, colStart, colEnd, rowStart, rowEnd)
On each call of the recursiveDivision function i update a blockedNodes set by adding value:
for (let i = colStart; i < colEnd; i++) {
blockedNodes.add(`c${i}r${wallStart}`);
}
If I console.log blockedNodes set inside recursiveDivision function, I'm getting desired result, for example:
Set(43) {'c0r7', 'c1r7', 'c2r7', 'c3r7', 'c4r7', …}
However when I console.log blockedNodes set inside recursiveDivisionWrap and not in recursiveDivision, I'll get comma separated object:
c0r7,c1r7,c2r7,c3r7,c4r7,c5r7,c6r7,c7r7,c8r7,c9r7,c9r0,c9r1,c9r2,c9r3,c9r4,c9r5,c9r6,c8r0,c8r1,c8r2,c8r3,c8r4,c8r5,c8r6,c3r0,c3r1,c3r2,c3r3,c3r4,c3r5,c3r6,c4r6,c5r6,c6r6,c7r6,c4r1,c5r1,c6r1,c7r1,c4r5,c5r5,c6r5,c7r5
I've also tried with array and the result was the same.
Why doesn't it return Set(43) {'c0r7', 'c1r7', 'c2r7', 'c3r7', 'c4r7', …} if the blockedNodes set is defined outside the recursiveDivision function and inside recursiveDivisionWrap and why does the inner recursiveDivision function returns correct set?
I would appreciate any help in finding answer to that question.
This behaviour has nothing to do with the place where the output is made, but how the output is formatted.
You have these statements:
console.log(blockedNodes);
And:
console.log(`Is this a set? ${blockedNodes}`);
And:
let ecie = Array.from(blockedNodes);
console.log(`Is this an array? ${ecie}`)
They don't do the same thing.
console.log(blockedNodes) leaves the rendering to the console API, which may provide additional information, like the name of the constructor of the object (Set in this case), the number of items this collection has, ...etc. It may even add user-interface controls to expand/collapse the contents of the collection and potential nested data structures.
console.log(`Is this a set? ${blockedNodes}`) will implicitly call blockedNodes.toString() in order to produce the string. Unless toString has been overriden, that will render as [object Set], and so the total output will be "Is this a set? [object Set]".
console.log(`Is this an array? ${ecie}`) will also call the toString method, but this time on ecie, which is an array (as that is what Array.from returned). The toString method on arrays produces a comma separated list of the values, which explains the output you mentioned.

Sequelize.js setter function not working as I expect

I'm having trouble using the setter functions on my Sequelize js model properties.
What I want to do is when one property is given a value use that value to populate another property in the table at the same time.
In my model this is the code I have for the property in question...
date_time_paid: {
type:DataTypes.DATE,
set(val) {
const date = new Date(val);
this.setDataValue('date_time_paid', val); // set the the current property
this.setDataValue('month_paid', `${date.getFullYear()}-${(date.getMonth() + 1)}`); //also set another property on the same row
},
},
What I expect to happen is for the date_time_paid column to store the raw value and the month_paid column to store a string derived from it. But when I run my seeder to populate the table with test data the value for the month_paid column remains null.
Is this the correct use of a setter function?
If it is what have I done wrong that means it's not working?
I think you need a just a getter. Forget about date_time_paid and make getter for month_paid:
get month_paid(){
const date = new Date(this.date_time_paid);
return `${date.getFullYear()}-${(date.getMonth() + 1)}`;
}

iteration of a JSON containg objects

I am trying to write a function that takes pokemon’s name as an argument and find out which all pokemon have that name in their “next_evolution” field
Consider the following JSON dataset -
visit https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json
now for that, I've written the following function:
var infoOfPokemon = function(nameOfPokemon,allPokemon){
for(x in allPokemon){
if(allPokemon[x].next_evolution.includes(nameOfPokemon)){
console.log('pokemons found: '+allPokemon[x].name)
} else{
null
}
}
}
var nameOfPokemon =prompt('enter the name of Pokemon')
infoOfPokemon(nameOfPokemon,pokemonData.pokemon)
but it is returning an error which says
Uncaught TypeError: Cannot read property 'includes' nextEvolution.js:4090 of undefined
One or more of your pokemon does not have a 'next_evolution' field set (for example, the one with id 3 in your file). Hence allPokemon[x].next_evolution evaluates to undefined and you cannot read 'includes' on that.
Check for the existence of next_evolution, first.
if (allPokemon[x].next_evolution &&
allPokemon[x].next_evolution.includes(nameOfPokemon)) { ...
and find out which all pokemon have that name in their “next_evolution” field
That should make you think of filter. You want to filter the list of pokemon to find the matching ones.
But, as already pointed out, you need to be able to return false in your filter predicate if the pokemon you're testing does not have a next_evolution field. You can do that via testing, as suggested in another answer: pokemon.next_evolution && pokemon.next_evolution.includes..., or you can default it, as below: (pokemon.next_evolution || []).includes...
(Note though that both you original and that answer miss a step, which is to then collect that name properties from those next_evolution values.
So here is a simple function which should filter the list to find the correct items. To use it with a call to your API, I wrap it in a fetch call, and simply console.log the results. Obviously, you might well have other ways to call it.
const infoOfPokemon = (name, all) => all.filter(pokemon =>
(pokemon.next_evolution || []).map(p => p.name).includes(name)
)
fetch('https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json')
.then(resp => resp.json())
.then(allPokemon => console.log(
infoOfPokemon('Butterfree', allPokemon.pokemon) //~> [{Caterpie}, {Metpod}]
))
You cannot use includes function directly on array having objects instead of single object. It will give false as output.
For e.g:
var pets = [{'name':'cat'},{'name':'dog'},{'name':'bat'}];
console.log(pets.includes("cat")) //false
This results in false always.
Proper way is to use a map to get a particular object field on which you want to use includes function.
e.g:
var pets = [{'name':'cat'},{'name':'dog'},{'name':'bat'}];
console.log(pets.map((obj)=> obj.name).includes("cat")); //true
In Your case first see if allPokemon[x].next_evolution is undefined or not (i.e next_evolution key is present or not)
code becomes:
if (allPokemon[x].next_evolution &&
allPokemon[x].next_evolution.(obj)=> obj.name).includes(nameOfPokemon)) { ...

Value returned by getcol function in jqgrid

I have a grid using jqgrid. I need to store the some data returned by the url:, in a local variable so that I can display it in the subgrid. For this I add that column as a hidden column in the main grid, which is of the format in json:
"Details":[{"Name":"ttt", "Quantity":"12"}] .
Then in the loadcomplete: function I save the value to a variable using
var griddata = $("#grid').getCol('Details', false);
Now when I access griddata[0], I get a object Object. I tried to parse it to get the values correctly, but to no avail. I tried:
griddata[0].Details.Name
or
griddata[0].Details.0.Name
or
griddata[0].Name,
but all failed. I guess I am missing the format if the data returned by the getcol() function.I looked up the documentation on the method and it says that it returns just the values when we specify false, but could not get any examples.
If there are any examples or if there are any pointer to the solution, it will be greatly appreciated.
If you check the type of griddata[0] (for example with typeof operator) you will see that it has type of string - this is because the value you are getting is the result of toString() on the object you have passed. The reason for that is the way in which jqGrid is treating values.
If you want to store JSON as the value, you need to stringify it entirely:
"Details": "[{\"Name\":\"ttt\", \"Quantity\":\"12\"}]"
Now you can deserialize those string values into objects like this:
var griddata = $.map($("#grid").jqGrid('getCol', 'Details', false), function(value) {
return JSON.parse(value);
});
After that you can access the objects in the way you want:
var name = griddata[0].Name;
var quantity = griddata[0].Quantity;
As an alternative you can split your object into two columns, so the values can be accessed directly with getCol.

Categories

Resources