Check that array of objects has all required keys - javascript

I have an object like this :
var field_arr = [{name:name},{email:email},{tel:tel}];
How to get the value of name, email or tel (property key) ? I want to use a loop to prompt user what is missing. For example, if user missed tel, there will be an alert saying tel is missing.

I don`t think you need it to be an array. Just loop over all the properties of your JSON object.
var obj = {
name: "name",
email: "",
tel: "tel"
};
$.each(obj, function(key, value) {
if (value == "") {
console.log(key + ": " + value);
}
});

Assuming you are storing those values from some fields with jQuery or something else. you can do something like :
var field_arr = [{name:"name"},{email:""},{tel:"lol"}];
jQuery.each(field_arr,function(obj){
for (var i in obj) {
if (obj[i].trim() === "") {
console.log(i + " is missing");
}
}
});

Assuming filed_arr is user input and you can't change the form of it and you want to compare it with required fields
var field_arr = [{name:'abc'},{email:'xyz'}];
var required = ['name', 'email' , 'tel'];
var inputKeys = field_arr.reduce(function(prev,next){
return prev.concat(Object.keys(next));
},[]);
document.write('<pre>inputKeys => ' +inputKeys+'</pre>');
var missingKeys = required.filter(function(key){
return inputKeys.indexOf(key) == -1;
});
document.write('<pre>missingKeys => ' +missingKeys+'</pre');
alert('You are missing '+missingKeys);

You want to :
turn your field_arr object into a key=>value type object
then loop on your required list to check that each item is a key in that object :
Code :
var arr = {};
for(var i=0; i<field_arr.length; i++){
var key = Object.keys(field_arr[i])[0];
arr[key] = field_arr[i][key];
}
// At this point you have a key => value type array in "arr"
var required_list = ["name", "email", "tel"];
for(var i=0; i<required_list.length; i++){
var item = required_list[i];
if(! item in arr) {
alert(item+" is missing");
}
}
If you want to use forEach instead of a for loop :
var arr = {};
field_arr.forEach(function(obj){
var key = Object.keys(obj)[0];
arr[key] = obj[key];
});
}
// At this point you have a key => value type array in "arr"
var required_list = ["name", "email", "tel"];
required_list.forEach(function(item){
if(! item in arr)
alert(item+" is missing");
});

Related

Javascript check if url param exists

I'm running an A/B test to see if showing more items is better for conversion. But it seems that the code sometimes causes errors.. But I can't find any errors and don't know when they occur.
In my test I check whether the url param IC exists and if it doesn't exists I will add this.
This is my code:
function checkIfAlreadyPaginated()
{
var field = 'IC';
var url = window.location.href;
if(url.indexOf('?' + field + '=') != -1)
return true;
else if(url.indexOf('&' + field + '=') != -1)
return true;
return false;
}
function insertParam(key, value) {
key = encodeURIComponent (key); value = encodeURIComponent (value);
var kvp = document.location.search.substr(1).split('&');
if (kvp == '') {
return '?' + key + '=' + value;
}
else {
var i = kvp.length; var x; while (i--) {
x = kvp[i].split('=');
if (x[0] == key) {
x[1] = value;
kvp[i] = x.join('=');
break;
}
}
if (i < 0) { kvp[kvp.length] = [key, value].join('='); }
return '?'+kvp.join('&');
}
}
var itemsPerPage = 48;
if(!checkIfAlreadyPaginated())
{
document.location.search = insertParam('IC', itemsPerPage);
}
Does someone spot possible issues? I'm running the test via VWO.com.
If there is a Javascript error you should see it in the browser console and share it with us.
In any case, I would do it by creating a JS Object first. I find it easier to work with.
In the following code I added the option to do the checking for multiple params of the querystring. If you only need to check the IC you can simplify it a bit. I tested it on a blank test.html.
<script type="text/javascript">
// get the current params of the querystring
var querystringItems = document.location.search.substr(1).split('&');
// create an object
var querystringObject = {};
for(i=0;i<querystringItems.length;++i) {
param = querystringItems[i].split('=');
querystringObject[param[0]] = param[1];
}
// Define the keys to be searched for and their default value when they are not present
var requiredKeys = {"IC":48, "test": "me"};
// Do the checking on the querystringObject for each requiredKeys
var doreload = false;
for (var key in requiredKeys) {
if (typeof querystringObject[key] == 'undefined') {
doreload = true;
// Create the missing parameter and assign the default value
querystringObject[key] = requiredKeys[key];
}
}
// If any of the requiredKeys was missing ...
if (doreload) {
// rebuild the querystring
var querystring = '?';
for (var key in querystringObject) {
querystring+=key+'='+querystringObject[key]+'&';
}
querystring=querystring.substr(0,querystring.length-1);
// reload page
document.location.search = querystring;
}
// assign the values to javascript variables (assuming you had it like this because you needed it)
var itemsPerPage = querystringObject.IC;
</script>
Here is an example to check this:
//get URL params into string:
paramStr = window.location.substring(window.location.indexOf('?'), window.location.length;
//turn string into array
paramArray = paramStr.split('&');
//prepare final array of params
params = {};
//prepare the index of IC parameter
icLoc = -1; //this is negative 1 so that you know if it was found or not
//for each item in array
for(var i in paramArray){
//push its name and value to the final array
params.push(paramArray[i].split('='));
//if the parameter name is IC, output its location in array
if(params[i][0] === 'IC'){
icLoc = i;
}
}
If IC is not found, icLoc will be -1.
If it is found, the value of IC in the URL parameters is params[icLoc][1]
Example result for query string ?foo=bar&code=cool&IC=HelloWorld:
params = {'foo': 'bar', 'code': 'cool', 'IC': 'HelloWorld'}
icLoc = 2
Example for query string ?foo=bar&code=cool:
params = {'foo': 'bar', 'code': 'cool'}
icLoc = -1
Here id is the param I'm using for a test. Pass the argument which you want to check whether it exists or not.
function queryParamExistUrl(param = '') {
if (new URLSearchParams(window.location.search).get(param) != null)
return true
return false
}
console.log(queryParamExistUrl('id'))

Getting the Item of Array by name of param

for (...) {
files.push(files[i]);
li_out.push({name : fileName, list_files : files});
}
How to get the Array of list_files by name?
var list_files_of_file3 = li_out[name == "file3" (?????)].list_files;
Array#find can be used in this case.
var list_files_of_file3 = li_out.find(o => o.name === "file3").list_files;
// Variable names changed for DEMO purpose
var files = [];
for (var i = 0; i < 10; i++) {
files.push({
name: 'fileName ' + i,
list_files: 'something ' + i
});
}
var res = files.find(o => o.name === 'fileName 3').list_files;
console.log(res);
How to get the Array of list_files by name?
using filter, try
var result = li_out.filter(function(item){ return item.name == "file3" });
Is it also possible to just return a property of the matching items
instead of the whole object? (below comment #MajidFouladpour)
Once you have got the result
var propertyNames = result.map(function(obj){ return obj.propertName; })

Cannot read 'xyxyx' property of undefined even if element exist

I have two HTML inputs (type="email", type="number") and my Angular app watches them using $formatters and $parsers. The errors are stored in an array and when user insert an email which contains "#gmail" the error is removed from the array.
app.controller('form1Controller', function($scope, UserService) {
$scope.formCompleted = false;
$scope.errors = UserService.errors;
//handle the user email input.
$scope.storeEmailErr = function(data) {
var correctKey = "#gmail";
var key = "#userEmail";
var res = {};
if (data != null) {
res = $scope.handleError(data, emailIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
UserService.errors = res[0];
emailIn = res[1];
}
};
//handle the user email input.
$scope.storeIdErr = function(data) {
var correctKey = "0000";
var key = "#userId";
var res = {};
if (data != null) {
res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
idIn = res[1];
}
};
}
This is the code that adds and removes errors from array. And here i suppose is the problem
function theIndexOf(val) {
console.log("find index in array of length: " + errorsDescription.length)
for (var i = 0; i < errorsDescription.length; i++) {
if (errorsDescription[i].selector === val) {
return i;
}
}
}
app.run(function($rootScope){
$rootScope.handleError = function(data, elemIn, correctKey, key, errorArray){
var idx = theIndexOf(key);
console.log("get index >>>>> " + idx);
var obj = errorsDescription[idx];
//if user didn't put correct word i.e. #gmail or 0000
if (data.indexOf(correctKey) < 0) {
if (!elemIn) {
errorArray.push(obj);
elemIn = true;
}
} else {
if (elemIn) {
$.each(errorArray, function(i){
if(errorArray[i].selector === key) {
errorArray.splice(i, 1);
elemIn = false;
}
});
}
}
return [errorArray, elemIn];
}
});
The problem is that when I insert i.e. "test#gmail.com", the error is deleted from the array and when I insert correct data again it tells me that cannot read 'yyy' property of undefined.
Here is my plunker.
https://plnkr.co/edit/l0ct4gAh6v10i47XxcmT?p=preview
In the plunker, type in the fields 'test#gmail' and test0000 for the Number, then remove data then insert again the same data to see the problem
Any help would be much appreciated!
EDIT: Working plunkr here: https://plnkr.co/edit/8DY0Cd5Pvt6TPVYHbFA4
The issue is here:
var obj = errorsDescription[idx];
//if user didn't put correct word i.e. #gmail or 0000
if(data.indexOf(correctKey) < 0){
// console.log("You must put correct word");
if(!elemIn){
errorArray.push(obj);
elemIn = true;
}
}
When your Personal Number error is removed, the logic above pushes undefined to your errorArray (because elemIn is false). Your storeIdErr methond:
$scope.storeIdErr = function(data){
var correctKey = "0000";
var key = "#userId";
var res = {};
if(data != null){
res = $scope.handleError(data, idIn, correctKey, key, $scope.errors);
$scope.errors = res[0];
idIn = res[1];
}
};
reads this value (res[0]) and stores it in $scope.errors which ultimately is iterated over on the next input event by:
function theIndexOf(val){
console.log("find index in array of length: " + errorsDescription.length)
for(var i = 0; i < errorsDescription.length; i++){
if(errorsDescription[i].selector === val){
return i;
}
}
}
due to your factory returning that object when asked for errors. To fix this, you should keep a static list that you never remove from which provides the error definitions. This is what you should refer to when you push to errorArray in your first code block.
The issue you are having is with this block of code here:
$.each(errorArray, function(i){
if(errorArray[i].selector === key) {
errorArray.splice(i, 1);
elemIn = false;
}
});
When you call splice, you are modifying the length of the array. $.each is looping over the length of the array, and is not aware of the length change. (I don't know the internal workings of $.each, but I'm guessing it caches the length of the array before starting, for performance reasons.) So, after you splice out the first error, the loop is still running a second time. At this point, errorArray[1] no longer exists, which is causing your undefined error.
See this question for reference: Remove items from array with splice in for loop

javascript loop form values by name then element id

I have loop going though form values, it is working fine throwing out the values based on the input name. But I would also like to be able to target by specific element id.
This is an example form:
_inputFields: function() {
var rows = [];
for(var i = 1; i <= 12; i++) {
var placeHolder = 'Intro text line ' + i;
var inputID = 'inputIntroText ' + i;
rows.push(<input type="text" className="form-control input-size-lg" name="formInput" id="inputText" placeholder={placeHolder}/>);
rows.push(<input type="text" className="form-control input-size-lg" name="formInput" id="inputTime" placeholder={placeHolder}/>);
}
So I can loop through and grab everything by name i.e. 'formInput' but how can I then grab formInput[inputText] and formInput[inputTime]?
This is my current loop through the values :
// gather form input
var elem = document.getElementsByName('formInput');
console.log(elem);
// Build the object
var obj = {
"DataObject": {
"user": {
"-name": "username"
},
"contentFile": {
"-filename": "Breaking_News",
"lock": {
"-fileIsBeingEdited": "false"
},
"content": {
"line": []
}
}
}
};
var line = obj.DataObject.contentFile.content.line;
for (var i = 0; i < elem.length; i++) {
if (elem[i].value != '') {
line.push({
"-index": i,
"-text": elem[i]['inputText'].value,
"-time": elem[i]['inputTime'].value
});
}
};
If I try:
"-text": elem[i]['inputText'].value,
"-time": elem[i]['inputTime'].value
I get the error: Cannot read property 'value' of undefined
This errors because elem[i]['inputText'] is undefined. This is because you are trying to lookup the inputText property of the element, which doesn't exist.
elem is an array, so I'd recommend using something like filter.
"-text": elem.filter(function(item) {
return item.id === 'inputText';
})[0].value;
Also, you should remove the for loop or you will get a duplicate line.
function getElementById(elems, id){
return elems.filter(function(item) {
return item.id === id;
})[0];
}
var line = obj.DataObject.contentFile.content.line;
line.push({
"-text": getElementById(elem, 'inputText').value,
"-time": getElementById(elem, 'inputTime').value
});
Here's an example jsfiddle.
You can use elem[i].id:
var line = obj.DataObject.contentFile.content.line;
for (var i = 0; i < elem.length; i++) {
if (elem[i].value != '') {
line.push({
"-index": i,
"-text": elem[i].id
// Since you are looping through the inputs, you will get the `inputTime` in the 2nd iteration.
});
}
};

Javascript array change value recursively

I'm stucking at changing an value of an array with unknown depth.
I want to iterate over it and change specific values, after all changes are done I want to receive the whole array back with the applied changes.
Code sample:
var array = [];
array.name = "Page";
array.inside = [];
array.inside.name = "Page inside";
array.inside.inside = [];
array.inside.inside.name = "Page inside inside";
array.inside.inside.inside = [];
function changeValue(array) {
for (var ii in array) {
if (typeof array[ii] === 'object') changeValue(array[ii]);
if (array.name) {
array.name = array.name + " changed";
}
console.log(array);
}
}
changeValue(array);
Try this:
var array = [];
array.name = "Page";
array.inside = [];
array.inside.name = "Page inside";
array.inside.inside = [];
array.inside.inside.name = "Page inside inside";
array.inside.inside.inside = [];
function changeValue(array) {
if (array.name) {
array.name = array.name + " changed";
}
console.log(array);
for (var ii in array) {
if (typeof array[ii] === 'object') changeValue(array[ii]);
}
}
changeValue(array);
Every time through the loop you are changing array.name. That is why you're results have ' changed changed'. Take the array.name modification out of the loop and it works just as expected.
Good luck.

Categories