Vuejs vuelidate array for object - javascript

I have a problem with the Vue vuelidate. Every time the boxes in the picture are pressed, an object is sent to an array. All boxes can be selected.
The condition is that a maximum of 3 boxes must be selected, if more than 3 are selected, I don't want to send the form.
Below is the code that runs when any box is pressed.
valueSelected(value,index) {
// console.log(index)
// console.log(value)
const i = this.mySelectedValue.indexOf(value)
// console.log('const i',i)
if (i === -1) {
this.mySelectedValue.push(value)
} else {
this.mySelectedValue.splice(i, 1)
}
const findIndex = this.user.positions.findIndex(v => {
return v.position === value.position
})
if (findIndex === -1) {
this.user.positions.push(value)
} else {
this.user.positions.splice(findIndex, 1)
}
},

Considering this is the whole function you call. You can just put an if around it so if 3 options are already selected then it will not trigger. I think this is the easy way out.
valueSelected(value,index) {
// console.log(index)
// console.log(value)
const i = this.mySelectedValue.indexOf(value)
// console.log('const i',i)
if (i === -1) {
if(this.mySelectedValue.length < 3){
this.mySelectedValue.push(value)
}
} else {
this.mySelectedValue.splice(i, 1)
}
const findIndex = this.user.positions.findIndex(v => {
return v.position === value.position
})
if (findIndex === -1) {
if(this.user.positions.length < 3){
this.user.positions.push(value)
}
} else {
this.user.positions.splice(findIndex, 1)
}
},

Related

How to write a state machine to solve the Count the smiley faces?

I have solved the problem Count the smiley faces:
Given an array (arr) as an argument complete the function countSmileys that should return the total number of smiling faces.
Rules for a smiling face:
Each smiley face must contain a valid pair of eyes. Eyes can be marked as : or ;
A smiley face can have a nose but it does not have to. Valid characters for a nose are - or ~
Every smiling face must have a smiling mouth that should be marked with either ) or D
No additional characters are allowed except for those mentioned.
Valid smiley face examples: :) :D ;-D :~)
Invalid smiley faces: ;( :> :} :]
Example
countSmileys([':)', ';(', ';}', ':-D']); // should return 2;
countSmileys([';D', ':-(', ':-)', ';~)']); // should return 3;
countSmileys([';]', ':[', ';*', ':$', ';-D']); // should return 1;
Note
In case of an empty array return 0. You will not be tested with invalid input (input will always be an array). Order of the face (eyes, nose, mouth) elements will always be the same.
Then when I look through the solutions I find that many people use regexp. Then I want write a state machine to implement regexp and solve this problem. But I failed. This is my code:
function countSmileys(smileys) {
let state = smileyHasValidEye;
return smileys.filter(smiley => {
for (let s of [...smiley]) {
state = state(s);
}
return state === true;
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return;
}
console.log(countSmileys([':)', ';(', ';}', ':-D']));
And the error I get is:
state = state(s);
^
TypeError: state is not a function
Then I debugged my code I found the procedure doesn't enter the smileyHasValidNose function. Then I don't know the reason.
The problem is you don't really reset state in between smileys. So the next smiley state will be true which you can't call (it's not a function).
You could use a local variable for state that resets it to the first function (the first step).
function countSmileys(smileys) {
let firstStep = smileyHasValidEye;
return smileys.filter(smiley => {
let state = firstStep;
for (let s of [...smiley]) {
state = state(s);
}
return state === true;
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return;
}
console.log(countSmileys([':)', ';(', ';}', ':-D']));
This code however, will error if there's more on the string besides the smiley (or a partial of the smiley).
I would change smileyHasValidMouth to return false if it doesn't detect a smiley. Just to be more consistent here...
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return false;
}
And adjust your loop to exit early if it finds a value that is not a function.
for (let s of [...smiley]) {
state = state(s);
if(typeof state !== 'function') return state;
}
function countSmileys(smileys) {
let firstStep = smileyHasValidEye;
return smileys.filter(smiley => {
let state = firstStep;
for (let s of [...smiley]) {
state = state(s);
if (typeof state !== 'function') return state;
}
}).length;
}
function smileyHasValidEye(s) {
if (s === ':' || s === ';') {
return smileyHasValidNose;
}
return smileyHasValidEye;
}
function smileyHasValidNose(s) {
if (s === '-' || s === '~') {
return smileyHasValidMouth;
}
return smileyHasValidMouth(s);
}
function smileyHasValidMouth(s) {
if (s === ')' || s === 'D') {
return true;
}
return false;
}
console.log(countSmileys([':~(', ':>', ':D', ':(', ':o>', ';)', ':)']));

More efficient or concise method for this function?

I have a data set of exercises that can be done when working out, in JSON format. I'm implementing a filtering system on this data, which has three different types of filters users can apply: sort filter, (which takes the current set of exercises and orders them by name a-z or vice versa), muscle group (exercises that fall under the same targeted muscle group) and training program (exercises that fall under the same training program).
Users should be able to select any of the filters and it will apply it straight away, but not all 3 types of filters have to be applied. Therefore, I have come up with the following function in JS:
function applyFilters(filters) {
const sort = filters[0];
const muscles = filters[1];
const programs = filters[2];
const exerciseJSONData = "exercises.json";
$.getJSON(exerciseJSONData, {
format: JSON,
}).done(function (result) {
let filteredArr = [];
if (muscles.length === 0 && programs.length === 0) {
filteredArr = result;
} else if (muscles.length !== 0 && programs.length === 0) {
$.each($(result), function (key, val) {
if (muscles.some((item) => val.MainMuscleGroup.indexOf(item) >= 0)) {
filteredArr.push(this);
}
});
} else if (muscles.length === 0 && programs.length !== 0) {
$.each($(result), function (key, val) {
if (programs.some((item) => val.TrainingProgram.indexOf(item) >= 0)) {
filteredArr.push(this);
}
});
} else {
$.each($(result), function (key, val) {
if (
muscles.some((item) => val.MainMuscleGroup.indexOf(item) >= 0) &&
programs.some((item) => val.TrainingProgram.indexOf(item) >= 0)
) {
filteredArr.push(this);
}
});
}
$("#number-of-exercises").text(filteredArr.length + " Exercises Found");
$("#exercises").empty();
createExerciseHTML(filteredArr);
});
}
This function works as intended, however, I think the readability of the if else statement could be hard to understand for others and breaks the rule of not repeating code. I am wondering if there is a more concise and efficient way of coding this function? Thanks in advance.
P.S. Sorry if there was too much info at the beginning of this post, I wanted to give some context to avoid any confusion readers may have.
You can start by taking the $each out and keep the if in the each.
function applyFilters(filters) {
const sort = filters[0];
const muscles = filters[1];
const programs = filters[2];
const exerciseJSONData = "exercises.json";
$.getJSON(exerciseJSONData, {
format: JSON,
}).done(function (result) {
let filteredArr = [];
var hasMuschle = muscles.length > 0 ? 1 : 0;
var hasProgram = programs.length > 0 ? 1 : 0;
var muscleAndProgram = hasMuschle - hasProgram;
$.each($(result), function (key, val) {
if (muscles.length === 0 && programs.length === 0) {
filteredArr = result;
} else if (muscles.length !== 0 && programs.length === 0) {
if (muscles.some((item) => val.MainMuscleGroup.indexOf(item) >= 0)) {
filteredArr.push(this);
}
} else if (muscles.length === 0 && programs.length !== 0) {
if (programs.some((item) => val.TrainingProgram.indexOf(item) >= 0)) {
filteredArr.push(this);
}
} else {
if (
muscles.some((item) => val.MainMuscleGroup.indexOf(item) >= 0) &&
programs.some((item) => val.TrainingProgram.indexOf(item) >= 0)
) {
filteredArr.push(this);
}
}
})
$("#number-of-exercises").text(filteredArr.length + " Exercises Found");
$("#exercises").empty();
createExerciseHTML(filteredArr);
});
}

How to do Event delegation for an Array?(or NodeList)

I'm trying to use the Event delegation/switch statement for the first time in my life, and I'm having trouble with for loop. When it was 'array[i]' it wasn't a problem. But now I'm removing the for loop to use the event delegation and putting it inside of a function, it keeps giving me errors, and I don't know what parameter can replace (and make the code work again) that array[i] in the new function. Any help or explanation will be appreciated.
//original code
const numbers = document.querySelectorAll(".number");
for (let i = 0; i < numbers.length; i++) {
numbers[i].addEventListener("click", function () {
if (display.value.length < 13) {
return;
}
if (display.value == "0" && numbers[i] != dot) {
display.value = numbers[i].innerText;
calculation = display.value;
} else {
if (numbers[i] == dot && display.value.includes(".")) {
return;
} else if (numbers[i] == dot && display.value == "") {
return;
} else {
display.value += numbers[i].innerText;
calculation = display.value;
}
}
buttonEffect(numbers[i], "number-active");
});
}
// New code
const numbers = document.querySelectorAll(".number");
function numberClick(number) {
if (display.value.length > 13) {
return;
}
if (display.value == "0" && this != dot) {
display.value = number.innerText;
calculation = display.value;
} else {
if (numbers == dot && display.value.includes(".")) {
return;
} else if (number == dot && display.value == "") {
return;
} else {
display.value += number.innerText;
calculation = display.value;
}
}
operatorOnOff = false;
buttonEffect(number, "number-active");
}
document.querySelector(".wrapper").addEventListener("click", (e) => {
switch (e.target.dataset.key) {
case "number":
numberClick();
break;
}
});
You pass the element that was the target of the click into numberClick and use it where previously you used numbers[i]. It looks like you're already doing the second part of that, and you even have a parameter declared for it, you just need to pass the element in:
numberClick(e.target);
Note that if your .number elements have child elements, target may be one of those child elements rather than .number. To handle that, you can use the DOM's relatively-new closest method, probably combined with contains to make sure it didn't match something surrounding .wrapper:
document.querySelector(".wrapper").addEventListener("click", (e) => {
const number = e.target.closest(".number");
if (number && this.contains(number) && number.dataset.key) {
numberClick(number);
}
});
There are polyfills you can use if you need to support obsolete browsers, or just do the loop yourself:
document.querySelector(".wrapper").addEventListener("click", (e) => {
let number = e.target;
while (number && !number.matches(".number")) {
if (this === number) {
return; // Reached the wrapper without finding it
}
number = number.parentElement;
}
if (number && number.dataset.key) {
numberClick(number);
}
});

How to make multiple conditions inside single filter

I am trying to make a filter based on checkboxes.
The thing is js ignoring other conditions inside filter when one is active
filterData() {
return this.airlines.filter(x => {
if (this.filters.options.length != 0 || this.filters.airlines.length != 0) {
for (let i = 0; this.filters.options.length > i; i++) {
if (this.filters.options[i] == 0) {
return x.itineraries[0][0].stops == 0;
}
if (this.filters.options[i] == 1) {
return x.itineraries[0][0].segments[0].baggage_options[0].value > 0;
}
}
} else {
return x;
}
})
}
I know that return will stop the current loop, but is there any way to do it correctly?
Update-1: (When to filter record for every case checked OR case)
Replace for loop and all conditions in a single return by && for if and || condition for data:
var chbox = this.filters.options;
return $.inArray(0, chbox) != -1 && x.itineraries[0][0].stops == 0
|| $.inArray(1, chbox) != -1 && x.itineraries[0][0].segments[0].baggage_options[0].value > 0;
Hope this helps !!
$.inArray(value, arr) method will check for each checkboxes and will work for every checked ones .
Update-2 (When to filter record for every case checked AND case)
As per comment below, you are trying to use checkbox on demand so use below code:
var chbox = this.filters.options;
boolean condition = true;
if ($.inArray(0, chbox) != -1) {
conditon = conditon && x.itineraries[0][0].stops == 0;
}
if ($.inArray(1, chbox) != -1) {
conditon = conditon && x.itineraries[0][0].segments[0].baggage_options[0].value > 0;
}
return condition;
Your filter function is returning an object, which ideally should be a boolean value. Please refactor the code as below.
filterData() {
return this.airlines.filter(x => {
let result = false;
if (this.filters.options.length != 0 || this.filters.airlines.length != 0) {
for (let i = 0; this.filters.options.length > i; i++) {
if (this.filters.options[i] == 0) {
result = x.itineraries[0][0].stops == 0;
break;
} else if (this.filters.options[i] == 1) {
result = x.itineraries[0][0].segments[0].baggage_options[0].value > 0;
break;
}
}
}
return result;
})
}

Javascript If Condition not evaluating correctly

I have a section of code where a variable contains a particular string (here it's multiply), and when I check if the variable has that particular string, the condition always equates to false. I cannot find what I'm missing here.
// calculations
$scope.$watch('colInput.' + el.key, function () {
angular.forEach($scope.colInput[el.key], function (item, index) {
angular.forEach($scope.column[el.key], function (item_1, index_1) {
if (item.hasOwnProperty(item_1.key)) {
item[item_1.key].type = item_1.type;
item[item_1.key].id = item_1.id;
item[item_1.key].options = item_1.options;
}
else {
item[item_1.key] = {};
item[item_1.key].type = item_1.type;
item[item_1.key].id = item_1.id;
item[item_1.key].options = item_1.options;
}
})
angular.forEach(item, function (elem, key) { //each column of the row
var operand_1, operator, operand_2;
if (elem.type == 10) {
// analyzing the formula
elem.options.forEach(function (el, index) {
if (isNaN(el) && index == 1) {
operator = el;
} else if (isNaN(el) && index == 0) {
operand_1 = el;
} else if (isNaN(el) && index == 2) {
operand_2 = el;
} else if (!isNaN(el)) {
operand_2 = parseFloat(el);
}
})
console.log(operator, eval(operator === "multiply"), typeof operator);
if (operator == 'multiply') {
console.log("IF---")
elem.value = parseFloat(item[operand_1].value) * operand_2;
}
}
})
})
}, true)
It looks like your operator is an HTML element not a String.
The comparison with multiply will always be false.

Categories

Resources