When setting value of object to true it looks and seems it changed it but I still cant use it(as it stayed false).
validateNextMove() {
Card.setArrayNextMoveValid(this.cardRepository.findAll(), false);
let client = this.clientRepository.findByTurn(true);
let provjera = 0;
if (client instanceof UNOClient) {
let cards = client.getCards();
for (let i = 0; i < cards.length; i++) {
if (this.cardCanBePlaced(cards[i])) {
provjera++;
cards[i].setNextMoveValid(true);
console.log(cards[i].getNextMoveValid());
console.log(provjera);
}
}
if (provjera == 0) {
for (let i = 0; i < cards.length; i++) {
cards[i].setNextMoveValid(true);
console.log(cards[i].getNextMoveValid());
console.log(provjera);
}
}
How do I fix this ?
this is my method for checking if card can be place:
cardCanBePlaced(card){
let current = this.discardDeck.slice(-1)[0];
if(typeof current === 'undefined'){
return true;
}
//Check if card is allowed
if(
card.getColor() === current.getColor()
){
return true;
}
return false;
}
if in above mtehod i add global variable to count if there is any available it still doesnt make it work, something like this(counter++ if there is available card of that color)
if(card.getColor()!= current.getColor() && counter==0){
return true;
}
Related
In my HTML page i have table in which each row, there is a check box.
My requirement is if more then one row is selected i.e. if the array length is 2, a toaster message has to be shown.
I got a use case there and it is,
if i select 2 rows(array length is 2), message is showing .
Then select 3rd row(array length is 3) and again deselect 3rd row(array length is 2 again).
Now also it shows the message. Here i don't want that toast.
My approach is :
$scope.toggleOne = function () {
if ($scope.selectedUsers.length === 2) {
showMessage();
}
for (var j = 0; j < $scope.users.length; j++) {
if (!$filter('filter')($scope.selectedUsers, $scope.users[j].id, true).length) {
$scope.selectAllCheckboxOfUsers = false;
return;
}
}
$scope.selectAllCheckboxOfUsers = true;
}
If you want to display the message just when going from 1 selected to 2 selected, you can check for that:
var previousSelectedNum = 0;
$scope.toggleOne = function () {
if ($scope.selectedUsers.length === 2 && previousSelectedNum === 1) {
showMessage();
}
// ...
previousSelectedNum = $scope.selectedUsers.length;
}
You can use a flag such as,
var isMessageShown = false;
Then in your function use as,
$scope.toggleOne = function () {
if($scope.selectedUsers.length === 1){
isMessageShown = false;
}
if ($scope.selectedUsers.length === 2 && !isMessageShown) {
isMessageShown = true;
showMessage();
}
for (var j = 0; j < $scope.users.length; j++) {
if (!$filter('filter')($scope.selectedUsers, $scope.users[j].id, true).length) {
$scope.selectAllCheckboxOfUsers = false;
return;
}
}
$scope.selectAllCheckboxOfUsers = true;
}
I have this for loop, and I would like to execute the else in the for loop only if none of the if conditions are met. The for loop runs until every item in the database has been checked. If none of the items in the database matches the user input then I want to run the else.
Right now, it runs the else right after the first try which means if the item matches is in the last row, it will just throw it in the error page since it stops the evaluation at the first iteration.
for(var i=0; i< rows.length; i++) {
if (rows[i].hashtag == userEnteredHashtag) {
// Display the choose Box page
res.render('chooseBox', {});
}
else {
// Display the invalid hashtag page
res.render('invalidHashtag', {});
}
}
Just move the else portion outside of the loop and execute it based on a flag
var wasFound = false;
for (var i = 0; i < rows.length; i++) {
if (rows[i].hashtag == userEnteredHashtag) {
// ...
wasFound = true; // set the flag here
}
}
if (!wasFound) {
res.render('invalidHashtag', {});
}
So add a check outside.
var hasMatch = false;
for (var i = 0; i < rows.length; i++) {
if (rows[i].hashtag == userEnteredHashtag) {
// Display the choose Box page
res.render('chooseBox', {});
hasMatch = true;
}
}
if (!hasMatch) {
// Display the invalid hashtag page
res.render('invalidHashtag', {});
}
Create a variable to track whether your condition has been met:
var isValid = true;
for(var i=0; i< rows.length; i++) {
if (rows[i].hashtag != userEnteredHashtag) {
isValid = false
}
}
isValid ? res.render('chooseBox') : res.render('invalidHashtag')
Another way to do it is to use filter and forEach.
var rows = [{hashtag: '#a'}, {hashtag: 'b'}, {hashtag: 'c'}];
var userEnteredHashTag = '#a';
var matchingRows = rows.filter(row => row.hashtag === userEnteredHashTag);
if (matchingRows.length) {
matchingRows.forEach(row => console.log(row));
} else {
console.log('invalid');
}
For example, if I have CSS that included within document:
div {
color: red;
}
div.test {
border: 1px solid blue;
}
and html tag within document body:
<div id='demo'>
<div class='test'>123</div>
<div>456</div>
</div>
I want to convert everything within #demo as a string containing tag with all styles it was using, such as:
var parent = $('#demo');
var result = convertExternalInternalStylesToInline(parent);
// the desired result:
result = '<div style="color: red; border: 1px solid blue;">123</div>' +
'<div style="color: red">456</div>'
What I need is the content of convertExternalInternalStylesToInline function, that automatically fetch all descendant elements, apply the calculated/used styles then add css styles to those elements, then return it all as html string.
Can it be done using only client side javascript? If yes, how?
(I need to know how to get all calculated/used styles for a tag)
minimal example:
function convertExternalInternalStylesToInline(parent) {
var parent = $(parent).clone(); // clone it before modify, is this deep clone?
parent.find('*').each(function(idx,el){ // fetch all children
var el = $(el); // convert to jquery object
// get all applied styles on this element
// el.? // --> don't know how
// apply css for each styles
el.css( css_prop, css_style );
});
// return as string, maybe:
return parent.html();
}
EDIT: Thanks to Winchestro, I looked up the window.getMatchedCSSRules function, which is actually only in Webkit, and there is a discussion that it should be deprecated.
What you should be using is actually the window.getComputedStyle() Read the docs at MDN.
Another very useful resource you may look into is the CSSUtilities set of libraries.
What you need are two separate things, a library to parse out your CSS Object Modal (CSSOM), and apply the relevant CSS to your DOM elements.
I know of a good nodejs library which does this called Juice.
There are is a library I found which would probably work on the front-end, called inlineresources, which has a browserified build
On second thoughts, I think you may be able to use Juice along with browserify for this... But you'll have to evaluate that possibility manually...
assuming you have the HTML in an array (lines: string[]):
I'm not sure why I spent so much time on this
let styleLines = this.getLinesInsideStyleTag(lines)
let htmlLinesSeparatedByTag = this.getLinesNotInsideStyleTag(lines)
let mapOfCSSrules = this.getMapOfCSSRuleNamesAndPropertiesFromCSSLines(styleLines)
let linesWithInlineRulesApplied = this.applyInlineStylesToLines(htmlLinesSeparatedByTag, mapOfCSSrules)
let finalString = ""
for(let v = 0; v < linesWithInlineRulesApplied.length; v++ ) {
finalString = finalString + linesWithInlineRulesApplied[v]
}
console.log(finalString)
getLinesInsideStyleTag(lines: any[]) {
let styleLines: any[] = []
let foundStylesStartTag = false
let foundStylesEndTag = false
for(let i = 0; i < lines.length; i++ ) {
if(lines[i].indexOf("<style ") != -1) {
foundStylesStartTag=true
} else if(lines[i].indexOf("</style>") != -1) {
foundStylesEndTag = true
}
if(foundStylesStartTag == true && foundStylesEndTag == false) {
if(lines[i].indexOf("<style") == -1 && lines[i].indexOf("</style") == -1) {
styleLines.push(lines[i])
}
}
}
return styleLines
}
getLinesNotInsideStyleTag(lines: any[]) {
let foundStylesStartTag = false
let foundStylesEndTag = false
let linesToKeep: any[] = []
for(let i = 0; i < lines.length; i++ ) {
if(lines[i].indexOf("<style ") != -1) {
foundStylesStartTag=true
} else if(lines[i].indexOf("</style>") != -1) {
foundStylesEndTag = true
}
if(foundStylesStartTag == false && foundStylesEndTag == false) {
linesToKeep.push(lines[i])
} else if(foundStylesStartTag == true && foundStylesEndTag == true) {
if(lines[i].indexOf("<style") == -1 && lines[i].indexOf("</style") == -1) {
linesToKeep.push(lines[i])
}
}
}
let actualLinesToKeep: any[] = []
for(let i = 0; i < linesToKeep.length; i++ ){
let thisLineSplitOnOpeningTag = linesToKeep[i].split("<")
let pushFullLine = false
let modifiedLine = ""
for(let y = 0; y < thisLineSplitOnOpeningTag.length; y++) {
if(thisLineSplitOnOpeningTag[0] !== "") {
pushFullLine = true
} else {
if(thisLineSplitOnOpeningTag.length > 2) {
//then the line contains nested tags (oof)
if(thisLineSplitOnOpeningTag[y].length > 0) {
if( y != thisLineSplitOnOpeningTag.length - 1) {
modifiedLine = modifiedLine + "<" + thisLineSplitOnOpeningTag[y]+"%*#"
} else {
modifiedLine = modifiedLine + "<" + thisLineSplitOnOpeningTag[y]
}
}
} else {
pushFullLine = true
}
}
}
if(pushFullLine == true) {
// console.log("3pushing full line because it doesn't have nested tags: "+linesToKeep[i])
actualLinesToKeep.push(linesToKeep[i])
} else {
actualLinesToKeep.push(modifiedLine)
}
}
// console.log("actualLinesToKeep: ")
// console.log(actualLinesToKeep)
return actualLinesToKeep
}
//e.g. you pass it
// myRule {
// color: blue;
// text-align: left;
// }
// you get back: a dictionary / map where "myRule" is the key, and "color: blue;" and "text-align: left;" are the values for that key.
getMapOfCSSRuleNamesAndPropertiesFromCSSLines(styleLines: any[]) {
// console.log("styleLines: ")
// console.log(styleLines)
//rule, properties
let CSSrules: Map<string,any[]> = new Map();
let rulesSplitOnClosingBracket = styleLines.toString().split("}")
for(let i = 0; i < rulesSplitOnClosingBracket.length; i++) {
let indexOfOpeningBracket = rulesSplitOnClosingBracket[i].indexOf("{")
let ruleName = rulesSplitOnClosingBracket[i].substring(0,indexOfOpeningBracket).trim()
ruleName = this.replaceAll(ruleName,",","").toLowerCase()
if(ruleName[0] === ".") {
ruleName = ruleName.substring(1)
}
//replace dots with a space
ruleName = ruleName.replace(/\./g,' ')
let propertiesOfThisRule = rulesSplitOnClosingBracket[i].substring(indexOfOpeningBracket+1).split(",")
let propertiesToKeep: any[] = []
for(let j = 0; j < propertiesOfThisRule.length; j++) {
propertiesOfThisRule[j] = propertiesOfThisRule[j].trim()
if(propertiesOfThisRule[j] !== undefined && propertiesOfThisRule[j].length > 0) {
propertiesToKeep.push(propertiesOfThisRule[j])
}
}
if(ruleName !== undefined && ruleName.length > 0 && propertiesToKeep !== undefined && propertiesToKeep.length > 0) {
CSSrules.set(ruleName, propertiesToKeep)
}
}
return CSSrules
}
applyInlineStylesToLines(htmlLinesSeparatedByTag: any[], mapOfCSSrules: Map<string,any[]>) {
let linesWithInlineRulesApplied: any[] = []
let ruleNames = Array.from(mapOfCSSrules.keys())
for(let r = 0; r < htmlLinesSeparatedByTag.length; r++) {
let lineSplitOnContinuationCharacter = htmlLinesSeparatedByTag[r].split("%*#")
let partsOfLineThatContainClosingTags: any[] = []
let partsOfLineThatDoNotContainClosingTags: any[] = []
for(let d = 0; d < lineSplitOnContinuationCharacter.length; d++) {
if(lineSplitOnContinuationCharacter[d].indexOf("</") != -1) {
partsOfLineThatContainClosingTags.push({orderNumber: d, line: lineSplitOnContinuationCharacter[d]})
} else if(lineSplitOnContinuationCharacter[d].indexOf("</") == -1) {
partsOfLineThatDoNotContainClosingTags.push({orderNumber: d, line: lineSplitOnContinuationCharacter[d]})
}
}
let orderNumbers1: any[number] = partsOfLineThatDoNotContainClosingTags.map(val => val.orderNumber)
let orderNumbers2: any[number] = partsOfLineThatContainClosingTags.map(val => val.orderNumber)
let maxOrderNumberFor1 = Math.max.apply(Math,orderNumbers1)
let maxOrderNumberFor2 = Math.max.apply(Math,orderNumbers2)
let maxOrderNumber: number;
if(maxOrderNumberFor1 > maxOrderNumberFor2) {
maxOrderNumber = maxOrderNumberFor1
} else {
maxOrderNumber = maxOrderNumberFor2
}
let thisActualLineWithStylesApplied = ""
for(let u = 0; u < maxOrderNumber+1; u++) {
let partOfLineWithoutClosingTag = partsOfLineThatDoNotContainClosingTags.filter(val => val.orderNumber == u)[0]?.line
let partOfLineWithClosingTag = partsOfLineThatContainClosingTags.filter(val => val.orderNumber == u)[0]?.line
if ( partOfLineWithoutClosingTag !== undefined ) {
let idxOfFirstSpace = partOfLineWithoutClosingTag.indexOf(" ")
for(let s = 0; s < ruleNames.length; s++) {
let applyThisRuleToThisLine = true
let textToCheckFor: any[] = ruleNames[s].split(" ")
for(let t = 0; t < textToCheckFor.length; t++) {
if(partOfLineWithoutClosingTag.indexOf(textToCheckFor[t]) == -1) {
applyThisRuleToThisLine = false
}
}
if(applyThisRuleToThisLine) {
let lineAfterApplyingStyle = partOfLineWithoutClosingTag.substring(0, idxOfFirstSpace) +" style=\""
for(let u = 0; u < mapOfCSSrules.get(ruleNames[s]).length; u++) {
let thisPropertyToApply = mapOfCSSrules.get(ruleNames[s])[u]
lineAfterApplyingStyle=lineAfterApplyingStyle+thisPropertyToApply
}
lineAfterApplyingStyle = lineAfterApplyingStyle +"\""
partOfLineWithoutClosingTag = lineAfterApplyingStyle + partOfLineWithoutClosingTag
let lastIndexOfLessThan = partOfLineWithoutClosingTag.lastIndexOf("<")
let lastIndexOfGreaterThan = partOfLineWithoutClosingTag.lastIndexOf(">")
partOfLineWithoutClosingTag = partOfLineWithoutClosingTag.substring(0,lastIndexOfLessThan) + partOfLineWithoutClosingTag.substring(lastIndexOfGreaterThan)
}
}
thisActualLineWithStylesApplied = thisActualLineWithStylesApplied + partOfLineWithoutClosingTag
}
if(partOfLineWithClosingTag !== undefined) {
thisActualLineWithStylesApplied = thisActualLineWithStylesApplied + partOfLineWithClosingTag
}
}
linesWithInlineRulesApplied.push(thisActualLineWithStylesApplied)
}
return linesWithInlineRulesApplied
}
Edit: Thanks to Kumar I realized my suggested method is nonstandard, and
getComputedStyle( element );
should be used instead, which is a bit more difficult to use and filter but has the advantage of giving you only the final rules that actually apply to the element after the CSS was evaluated (which also includes default, not explicitly declared styles, making it a bit trickier to use in this case).
getMatchedCSSRules( element );
just use this vanilla javascript function. It does exactly what you want. I'd explain it if there were anything to explain that isn't implied by the name of the function.
I have a select element with values adding up to it using a javascript function which also has a value selected by default.
Everything is fine when i use the google chrome debug mode to see what has gone wrong. If i come out of the debug mode, i cant see any values, even though they are loaded.
They seem to turn back when i scroll using the select elements.
Everything seems fine in Internet Explorer and Firefox though.
Anyone faced this issue before?
Adding the code here: function call has only first 3 variables set. childSelect1 is the select element i am talking about and childOptions1 are the available options for it. The options are added based on the value in parentSelect.
function toggleChildOptions(parentSelect, childSelect1, childOptions1, childSelect2, childOptions2, addBlankEntry)
{
if(childSelect1 == null && childSelect2 == null)
{
return;
}
if(childSelect1 != null)
{
childSelect1.options.length = 0;
}
if(childSelect2 != null)
{
childSelect2.options.length = 0;
}
for (var i = 0; i < parentSelect.length; i++)
{
if(parentSelect.options[i].selected)
{
var parentID = parentSelect.options[i].value;
if(childSelect1 != null)
{
var currentChildOption1Length = childSelect1.options.length;
if (addBlankEntry == true)
childSelect1.options[currentChildOption1Length++] = new Option('',-1);
for(var j = 0; j<childOptions1.length;j++)
{
if(childOptions1[j][1] == parentID)
{
childSelect1.options[currentChildOption1Length++] = new Option(childOptions1[j][2],childOptions1[j][0]);
if (childOptions1[j][2] == '')
child1BlankFound = true;
}
}
}
if(childSelect2 != null)
{
var currentChildOption2Length = childSelect2.options.length;
if (addBlankEntry == true)
childSelect2.options[currentChildOption2Length++] = new Option('',-1);
for(var v = 0; v<childOptions2.length; v++)
{
if(childOptions2[v][1] == parentID)
{
childSelect2.options[currentChildOption2Length++] = new Option(childOptions2[v][2],childOptions2[v][0]);
}
}
}
}
}
}
I am comparing two attributes of the same object to work out which one is larger, if one is larger then it sets another attribute to True.. else it sets it to false.
Here is my function:
country.prototype.cure = function(){
for (var i = 0; i<this.diseases.length; i++)
{
console.log(this.health);
console.log(this.diseases[i].cureLevel);
if (this.heatlh >= this.diseases[i].cureLevel)
{
this.diseases[i].cured = true;
createDiseaseTable();
}
else
{
this.diseases[i].cured = false;
}
}
}
NOTE: this.health = 39000000 and this.diseases[i].cureLevel = 2500000
The problem is that whenever I run the function, despite this.health being larger it will always miss the if and go straight to the else...
Try this:
country.prototype.cure = function(){
for (var i = 0; i<this.diseases.length; i++)
{
var a=parseInt(this.health);
var b=parseInt(this.diseases[i].cureLevel);
if (a >= b)
{
this.diseases[i].cured = true;
createDiseaseTable();
}
else
{
this.diseases[i].cured = false;
}
}
}