Why is *ngFor seemingly looping infinitley? - javascript

Can anyone help me understand why this ngFor seemingly gets to the end and then loops again?
Template
<div class="row">
<h2>Results</h2>
</div>
<div *ngFor="let bson of bsonResults; let i = index">
{{i}}
{{getItemContext(bson, i)}}
<!-- <mat-card class="card collection-card">
<a [routerLink]="toDetails(results.database, results.collection, bson.data._id.$oid)" data-toggle="tooltip"
title="Click to visit details page" attr.aria-label="Item Name: {{utility.getItemTitle(bson, results.nameField)}}">{{utility.getItemTitle(bson, results.nameField)}}</a>
<mat-card-content [innerHTML]="getItemContext(bson)">
{{getItemContext(bson)}}
</mat-card-content>
</mat-card> -->
</div>
Relevant methods from .ts file
getItemContext(bson, i) {
console.log(i);
console.log(bson);
if (this.searchCriteria.q !== '') {
return this.contextWithSearchString(bson);
} else {
return this.contextWithoutSearchString(bson);
}
}
contextWithSearchString(bson) {
let keys = Object.keys(bson.data);
let longString: string;
let highlightedText: string;
for (let key of keys) {
let bsonItem: string = bson.data[key];
bsonItem.toString();
if (typeof bsonItem === 'string') {
if (bsonItem.toUpperCase().includes(this.searchCriteria.q.toUpperCase())) {
let indexOfTerm = bsonItem.toUpperCase().indexOf(this.searchCriteria.q.toUpperCase());
if (bsonItem.length > 100) {
if (indexOfTerm - 50 <= 0) {
bsonItem = bsonItem.substring(0, 100) + '...';
} else {
bsonItem = '...' + bsonItem.substring(indexOfTerm - 50, indexOfTerm + 50) + '...';
}
}
if (longString === undefined) {
highlightedText = this.utility.highlight(bsonItem, this.searchCriteria.q);
longString = '<b>' + key + ': ' + '</b> ' + highlightedText + ' | ' ;
} else {
highlightedText = this.utility.highlight(bsonItem, this.searchCriteria.q);
longString = longString + '<b>' + key + ': ' + highlightedText + ' | ';
}
}
}
}
return longString;
}
contextWithoutSearchString(bson) {
let keys = Object.keys(bson.data);
let longString: string;
let i = 0;
keys.forEach(key => {
// only return strings in search context, and only return the first 4.
if (typeof (bson.data[key]) === 'string' && i < 4) {
let dataValue: string = bson.data[key];
if (dataValue.length > 100) {
dataValue = dataValue.substring(1, 100) + '...';
}
if (longString === undefined) {
longString = '<b>' + key + ': </b>' + ' ' + dataValue + ' | ';
} else {
longString = longString + '<b>' + key + ': </b> ' + dataValue + ' | ';
i++;
}
}
});
// if the item only contains objects (no strings) then just return 600 chars of the raw JSON.
if (longString === undefined) { return JSON.stringify(bson.data).substring(0, 600); } else {
return longString;
}
}
and here's how it looks on the page (..looks fine)
yet here is my console getting bombarded
Strangely enough the page is displaying the output from the getItemContext function on the page the correct amount of times. However, I put a console log at the start of the function to log my bson objects and this is continually filling up the console with objects. I stuck an index variable in to see if the count looked right and it does (bsonResults contains a 11 items). When the console has gotten up to logging out the 11th item it just starts again.

Related

How to make variables optional while concatenation of string?

I am manipulating string to display in UI, Data is being dynamically with below code sometime i don't get header and details so how to make IHeader and IResponse optional for the string concatenation below.
if i dont have IHeader it will break at IHeader.id and throw exception i want to display whatever data is available to render.
main.js
const data = [{
id: "header",
name: "IHeader"
}, {
id: "param",
name: "IParams"
}, {
id: "details",
name: "IResponse"
}]
function buildText(data) {
var IParams;
var IResponse;
var IHeader;
for (var item of data) {
if (item.id === "param") {
IParams = item;
} else if (item.id === "header") {
IHeader = item;
} else if (item.id === "details") {
IResponse = item;
}
}
var text = '';
text += app + '.setConfig({\n' + "env:" + getEnv() + '\n});' + '\n\n';
text += 'let param:' + IParams.name + ' ' + '=' + '' + JSON.stringify(request, null, 4) + ';\n\n';
text += ref + '(' + 'param,(result:' + ' ' + '{' + '\n' + IHeader.id + ':' + IHeader.name + '\n' + IResponse.id + ':' + IResponse.name + '\n' + '})' + ' ' +
' => {\n console.log(result); \n});';
}
1 - You can try to create an object with empty values. That'll prevent the exception.
emptyObject = {id: ""} // more empty keys, if there is
IParam = (item.id === "param") ? item : emptyObject
2 - Or ignore that concatenation of the variable if undefined or null.
if (Iparam) {
// concatenation ..
}

Print out each array value in the iteration, value is undefined

I want to print out the content of the composed array. As you can see I call console.log at the end of the code and every value in the composed array is undefined. But if I call console.log at somewhere else such as if statement, the values are right. Please tell me why, thanks!
$(function() {
var text = $('p').text().split('');
var letter = 0;
var composed = [];
$.each(text, function(index, value) {
if (/\w/.test(value)) { // if the character is alphanumeric
var prev = index - 1;
var next = index + 1;
if (/\w/.test(text[prev])) {
composed[letter] = composed[letter] + value;
if (!/\w/.test(text[next])) {
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
} else {
composed[letter] = value;
if (!/\w/.test(text[next])) {
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
}
} else {
composed[letter] = value;
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
console.log('composed[' + letter + '] = ' + composed[letter]); // undefined
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Test both Chinese中文 ,alphbets and numbers.</p>
console.log('composed[' + letter + '] = ' + composed[letter - 1]);
this gives correct value
your composed[letter] is "undefined" because previous state is letter++;
Perhaps you meant this?
var letter = 0;
var composed = [];
function addLetter(letter, value) {
// your could ignore white-space and punctuation there
if (composed[letter]) composed[letter] += value
else composed[letter] = value;
}
$(function() {
var text = $('p').text().split('');
$.each(text, function(index, value) {
if (/\w/.test(value)) { // if the character is alphanumeric
var prev = index - 1;
var next = index + 1;
if (/\w/.test(text[prev])) {
addLetter(letter, value)
if (!/\w/.test(text[next])) {
letter++;
}
} else {
addLetter(letter,value);
if (!/\w/.test(text[next])) {
letter++;
}
}
} else {
addLetter(letter, value)
letter++;
}
});
console.log(composed)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Test both Chinese中文 ,alphabets and numbers 1234.</p>
Just add a check for spaces. to ensure the we are not manipulating spaces.
**if (/\w/.test(text[prev] && composed[letter]!=" "))**
--
$(function() {
var text = $('p').text().split('');
var letter = 0;
var composed = [];
$.each(text, function(index, value) {
if (/\w/.test(value)) { // if the character is alphanumeric
var prev = index - 1;
var next = index + 1;
if (/\w/.test(text[prev] && composed[letter]!=" ")) {
composed[letter] = composed[letter] + value;
if (!/\w/.test(text[next])) {
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
} else {
composed[letter] = value;
if (!/\w/.test(text[next]) && composed[letter]!=" ") {
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
}
} else {
composed[letter] = value;
console.log('composed[' + letter + '] = ' + composed[letter]);
letter++;
}
console.log('composed[' + letter + '] = ' + composed[letter]); // undefined
});
});

Trying to grab a innerhtml from within a innerhtml

So i've recently ran into issues with trying to move specific pieces of a <p> </p> called result. as such i thought hey! wouldn't be easier to break each part inside of result down into another <p>!? well it works lol however trying to grab that inner <p> that in this cause we'll call vault is being difficult. I've tried several methods but cant seem to grab it's value from outside in a document.getElementByID....here's the code below for the html.
document.getElementById("result").innerHTML = Monster + "<p id='vault'> || HP: " + HP + "</p> || Defense: " + Def + " || Attack: " + ATK + " || Can it Dodge/Block: " + DB + " || Can it retaliate: " + RET + " || Initative: " + INT + " || Exp: " + MEXP + " <input type='submit' class='new' onclick='Combat(" + loop + ")' value='FIGHT!'></input>" + "<br><br>" + A;
}
then the script that eventually calls it
function Combat(id){
document.getElementById("vault").innerHTML = id;
document.getElementById("C").value = id
}
So what i'm trying is change id "C" to ID"VAULT" inside of id ("result").
any ideas on why i can't grab vault?
What you want would be easier with Object-oriented JavaScript.
Usually when coding JavaScript you want to be as independent of the DOM (HTML) as possible.
Consider the following example:
/**
* Monster
*/
var Monster = (function() {
function Monster(HP, DEF, ATK, DB, RET, INT, MEXP) {
if (HP === void 0) {
HP = 100;
}
if (DEF === void 0) {
DEF = 10;
}
if (ATK === void 0) {
ATK = 100;
}
if (DB === void 0) {
DB = 10;
}
if (RET === void 0) {
RET = true;
}
if (INT === void 0) {
INT = 100;
}
if (MEXP === void 0) {
MEXP = 100;
}
this.HP = HP;
this.DEF = DEF;
this.ATK = ATK;
this.DB = DB;
this.RET = RET;
this.INT = INT;
this.MEXP = MEXP;
}
/**
* getHTML
*/
Monster.prototype.getHTML = function() {
return "HP: " + this.HP + " || Defense: " + this.DEF + " || Attack: " + this.ATK + " || Can it Dodge/Block: " + this.DB + " || Can it retaliate: " + this.RET + " || Initative: " + this.INT + " || Exp: " + this.MEXP;
};
/**
* attacked
*/
Monster.prototype.attacked = function(damage) {
if (damage === void 0) {
damage = 0;
}
//check defences
if (damage > this.DEF + this.DB) {
//take damage
this.HP -= (damage - this.DEF + this.DB);
}
if (this.HP < 0) {
//Return true if it slew the monster
return true;
} else {
//Return false if the monster survived
return false;
}
};
return Monster;
}());
/**
* Area
*/
var Area = (function() {
function Area(name) {
if (name === void 0) {
name = "Vault";
}
this.name = name;
this.monsters = [];
}
/**
* addMonster
*/
Area.prototype.addMonster = function(monster) {
this.monsters.push(monster);
return this;
};
/**
* attackVault
*/
Area.prototype.assault = function(damage) {
if (damage === void 0) {
damage = 0;
}
//If no monster
if (this.monsters.length < 1) {
alert("You have cleared this vault");
return true;
} else {
//If monsters exists, attack the first
var monsterKilled = this.monsters[0].attacked(damage);
//If the monster was killed
if (monsterKilled) {
//remove monster
this.monsters.splice(0, 1);
//Alert the player
alert("Well done hero!\nOnly " + (this.monsters.length) + " remaining!");
}
}
//Return maybe monsters left?
return this.monsters.length < 1;
};
return Area;
}());
////GRAP HTML ELEMENT
var output = document.getElementById("current-monster");
////RUNNING YOUR GAME
//Build and populate world
var vault = new Area();
vault
.addMonster(new Monster())
.addMonster(new Monster());
//INTERACTION
alert("Start");
//Hit the vault till it is empty
while (vault.assault(45) != true) {
output.innerHTML = vault.monsters[0].getHTML();
alert("Attack!");
}
output.innerHTML = "Victory!";
<h1 id="title">Monster Game!</h1>
<h2 id="current-monster"></h2>
See how i can easily access the data though JavaScript?
When coding a JavaScript game, it makes sense to keep important data and structures in your JavaScript.
Ok so i added the bit - ADyson suggested...
document.getElementById("result").innerHTML = Monster + "<p id='vault(" + loop + ")'> || HP: " + HP + "</p>" + " || Defense: " + Def + " || Attack: " + ATK + " || Can it Dodge/Block: " + DB + " || Can it retaliate: " + RET + " || Initative: " + INT + " || Exp: " + MEXP + " <input type='submit' class='new' onclick='Combat(" + loop + ")' value='FIGHT!'></input>" + "<br><br>" + A;
}
}
}
function Chest(id){
window.open('LootGen.html', '_blank');
}
function Combat(id){
var id = document.getElementById("vault" + id).innerHTML;
document.getElementById("C").value = id;
submit();
}
However now when i run it on the " ).innerHTML;" i'm getting a
MonsterGen.html:426 Uncaught TypeError: Cannot read property
'innerHTML' of nullCombat # MonsterGen.html:426onclick #
MonsterGen.html:1
Ok I found out exactly was was going wrong; it was the naming convention in the <P>.
Originally it was id='vault(" + loop + ")'... this would make it vault(1) etc.... however the getElement was getting it by this call ("vault" + id) so it would call vault1....thus two separate id's entirely....that's why it was returning null.
So I removed the () in the equation and now everything is working beautifully.

InnerHTML Append Item instead of Replace

I'm trying to make a palindrome script and it's actually "working".
I want to make a improvement. I want the input value append on my "output" div.
here are my fiddle http://jsfiddle.net/vitorboccio/8yh1u0t7/
any hints ? I dont want to use Jquery ! Thanks!
(function () {
"use strict";
var output = document.getElementById("output"),
statusLine = document.getElementById("status"),
phrase = document.getElementById('phrase'),
testButton = document.getElementById("testButton"),
//palindromeText = document.getElementById("palindrome"),
characterCheck = document.getElementById("characterCheck"),
ignoreSpecialCharacters = false,
ignoreSpaces = false;
function setMessage(palindrome) {
if (palindrome) {
output.innerHTML = phrase.value + ' ' + "é palindroma";
} else {
output.innerHTML = phrase.value + ' ' + "não é a palindroma";
}
}
function checkForPalindrome(string) {
var palindrome = true,
right = string.length - 1,
left = 0;
if (!string || string.length < 1) {
// 0 characters
return false;
}
while (left < right && palindrome) {
palindrome = string.charAt(left) === string.charAt(right);
left++;
right--;
}
return palindrome;
}
function executeTest() {
var string = phrase.value,
cleanString;
cleanString = string;
if (ignoreSpaces) {
//ignores whitespaces only;
cleanString = string.replace(/\s+/g, '');
}
if (ignoreSpecialCharacters) {
//ignores punctuation and white space (controversial).
cleanString = string.replace(/[A-Z0-9]/ig, '');
}
if (checkForPalindrome(cleanString)) {
setMessage(true);
palindromeText.innerHTML = '"' + string + '"';
} else {
setMessage(false);
}
}
function executeOnEnter(e) {
if (e.keyCode === 13) {
executeTest();
// phrase.blur();
}
}
//resets the form to state 1
function resetForm() {
output.innerHTML = "";
//statusLine.innerHTML = "Waiting";
statusLine.style.color = "green";
phrase.value = "";
}
function charIgnoreChanged(e) {
ignoreSpecialCharacters = e.target.checked;
}
function spaceIgnoreChanged(e) {
ignoreSpaces = e.target.checked;
}
phrase.addEventListener('keydown', executeOnEnter);
testButton.addEventListener('click', executeTest);
characterCheck.addEventListener('change', charIgnoreChanged);
spaceCheck.addEventListener('change', spaceIgnoreChanged);
}());
You just need to modify setMessage
function setMessage(palindrome) {
if (palindrome) {
output.innerHTML += phrase.value + ' ' + "é palindroma<br />";
} else {
output.innerHTML += phrase.value + ' ' + "não é a palindroma<br />";
}
// for user convenience, clear the textbox and give it focus
phrase.value = '';
phrase.focus();
}
Fiddle
You can append to the div by keeping the original innerHTML like this:
output.innerHTML = output.innerHTML + "<br />" + phrase.value + ' ' + "é palindroma";
or shorter:
output.innerHTML += "<br />" + phrase.value + ' ' + "é palindroma";

JSON parsing in javascript

I'm trying to parse JSON in JavaScript. If my JSON data looks like below, I want to iterate through all the JSON elements that start with "custom" and not with any other string. How do I do this?
{
"fields": {
"custom12": {
value: "dsada"
},
"custom45": {
value: "adsadad"
},
"test12": {
value: "12323"
}
}
}​
var newObject = {}, key;
for(key in data.fields){
if(key.search(/custom/) > -1){
newObject[key] = data.fields[key];
}
}
console.log(newObject);
The following iterates the properties of the fields object and checks whether the property's name contains custom:
var data = yourObjectLiteral, i, current;
for(i in data.fields) {
if(i.indexOf('custom') > -1) {
current = data.fields[i];
// ... your logic ...
}
}
With the json string you provided I'd do it as such:
<script src="json2.js"></script>
<script>
var raw = '{'
+ ' "fields": {'
+ ' "custom12": {'
+ ' "value": "dsada"'
+ ' },'
+ ' "custom45": {'
+ ' "value": "adsadad"'
+ ' },'
+ ' "test12": {'
+ ' "value": "12323"'
+ ' }'
+ ' }'
+ '}';
var data = JSON.parse(raw);
var fields = data.fields;
var message = '';
for (var key in fields) {
if (key.indexOf('custom') === 0) {
message += key + ': ' + fields[key].value + '\n';
}
}
alert(message);
</script>
But, if you can rewrite the incomming message a little it will look simpler.
<script src="json2.js"></script>
<script>
var raw = '{'
+ ' "custom12": "dsada",'
+ ' "custom45": "adsadad",'
+ ' "test12": "12323"'
+ '}';
var fields = JSON.parse(raw);
var message = '';
for (var key in fields) {
if (key.indexOf('custom') === 0) {
message += key + ': ' + fields[key] + '\n';
}
}
alert(message);
</script>

Categories

Resources