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
Related
I'm creating a guest list program that stores the guest list in Firebase RTDB and when I check people in and out my function runs several times more than it is supposed to. I've sent alerts to the console so I know how many times it has run. I have separate functions for both check in and check out operations so it may be that I am calling my db too many times?
//-------------------- Check In and Check In Helper Functions -------------------------
//Helper Function to Grab current List index
function printArray() {
var ref = database.ref('guestList')
ref.on('value', readData, errData);
}
function readData(data){
guestList=[];
var scores = data.val();
var keys = Object.keys(scores)
for (var i=0; i < keys.length; i++){
var k = keys[i]
var name = scores[k].name;
var inside = scores[k].Inside;
var timeIn = scores[k].TimeIn;
var timeOut = scores[k].TimeOut;
guestList[i] = {
name: name,
Inside: inside,
TimeIn: timeIn,
TimeOut: timeOut,
}
}
checkIn(guestList);
}
function errData(err){
console.log('Error!');
console.log(err);
}
//Helper Function to set text box to selected name
function checkInn(name){
console.log(name)
document.getElementById('checkIn').value = name;
}
//Check in
function checkIn(list) {
//Grabs current guest to be added or deleted from form text box
var name = document.getElementById('checkIn').value;
//Checks to see if user is in list of guests and isn't in the list of guest in the party
var guestsRef = firebase.database().ref("guestList/");
guestsRef.orderByChild("name").on("child_added", function(data) {
if (name == data.val().name) {
objIndex = list.findIndex((obj => obj.name == name));
guestsRef = firebase.database().ref("guestList/" + objIndex)
guestsRef.update({
Inside: "Yes",
TimeIn: getTime(),
})
guestsRef.off();
document.getElementById('checkIn').value = "";
alerts(name, true)
}
})
}
//------------------------- Check Out ------------------------------------------------------------
//Helper Function to Grab current List index
function printArrayy() {
var ref = database.ref('guestList')
ref.on('value', readOutData, errData);
}
function readOutData(data){
guestList=[];
var scores = data.val();
var keys = Object.keys(scores)
for (var i=0; i < keys.length; i++){
var k = keys[i]
var name = scores[k].name;
var inside = scores[k].Inside;
var timeIn = scores[k].TimeIn;
var timeOut = scores[k].TimeOut;
guestList[i] = {
name: name,
Inside: inside,
TimeIn: timeIn,
TimeOut: timeOut,
}
}
checkOut(guestList);
}
//Helper Function to set text box to selected name
function checkOutt(name){
console.log(name);
document.getElementById('checkOut').value = name;
}
//Check Out
function checkOut(list) {
//Grabs current guest to be added or deleted from form text box
var name = document.getElementById('checkOut').value;
//Checks to see if user is in list of guests and isn't in the list of guest in the party
var guestsRef = firebase.database().ref("guestList/");
guestsRef.orderByChild("name").on("child_added", function(data) {
if (name == data.val().name) {
objIndex = list.findIndex((obj => obj.name == name));
guestsRef = firebase.database().ref("guestList/" + objIndex)
guestsRef.update({
Inside: "No",
TimeOut: getTime(),
})
document.getElementById('checkOut').value = "";
guestsRef.off();
alerts(name, false)
}
})
}
//Placeholder to alert user when a succesful check in or check out function runs
function alerts(name, Boolean){
if(Boolean){
console.log(name + " has been checked in!")
}
else{
console.log(name + " has been checked out!")
}
}
Here is the screenshot of my output. Thanks in advance!
Edit: Forgot to mention and apologize for my excessive use of helper functions! My HTML form calls printArrayy() and printArray first for each function!
have you tried once instep on, i mean:
ref.once('value', readOutData, errData); }
I am getting the above error when I run my function. The goal is when a user enters a number in a search box it should zoom to that number in the visualization. Below is my code -
function zoom1() {
var input1 = document.getElementById("myInput1").value; //value from searchbox
console.log("input from searchbox :"+input1);
d3.json("intervals.json", function(alldata) // entering json file to look for oid
{
// console.log("all data from json"+alldata);
var i=0;
for (i = 0; i < alldata.records.length; i++) //for loop for getting the "oid" alldata.records.length;
{
conceptid1 = alldata.records[i].eag; //saving all the oid in conceptid
console.log("conceptid1: "+conceptid1);
var conceptid2 = conceptid1.toString();
console.log("conceptid2: "+conceptid2);
if (conceptid2 === input1) //if the user input1 matches conceptid2
{
console.log("inside if conceptid2:"+conceptid2);
console.log(document.getElementById(conceptid2).dispatchEvent(new Event('click'))); // zoom
}
}
});
}
Can you share the console log for conceptid2?
By the way, use ES6 syntax. It's a newer and better way to write JS. Here is your code written in ES6:
const zoom = () => {
let value = document.querySelector("#myInput1").value;
console.log(`Input ${value}`);
d3.json("intervals.json", (alldata) => {
const { records } = alldata;
for (let i = 0; i < records.length; ++i) {
const conceptId = records[i].eag.toString();
console.log(`Concept ID: ${conceptId}`);
if (conceptId === value) {
// Your stuff
}
}
});
}
Anyways didn't want to come on too hard but I hope this helps :)
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'))
I currently use this script:
wHandle.setNick = function (arg) {
userNickName = arg;
var fnicks = ["porno","ibne","amcık","amcik","piç","salak","orospu","pkk","sik","kürdistan","kurdistan","kÜrdistan","kürt","sikeyim","sıkeyim","götoş","yönetici","YÖNETICI","YONETICI","yonetici","admın","admin","yarah","yarrah","agario","sike","s1ke","anan"];
var nctr = arg.toLowerCase();
if(fnicks.indexOf(nctr) > -1) {
alert("Unknown Nickname!");
} else {
hideOverlays();
sendNickName();
wjQuery("#mini-map-wrapper").show();
userScore = 0
wjQuery(".btn-needs-nick").prop("disabled", false);
}
};
I wanted to make some kind of filter, so that it blocks these nicknames BUT it isn't covering all of my cases. For example it blocks porno but not pornoo
I want it to use if(contains).
You've essentially done your logic backwards. Instead of checking if the nickname is in your block list, you'd be better served checking if an element of your blocklist is in your nickname like so:
var nick = args.toLowerCase();
for (var i; i < fnicks.length; i++) {
if (nick.indexOf(fnicks[i]) != -1) {
//bad name!
}
}
well I would just loop through the array, and search if the argument you pass (nctr in that case) contains the current entry (fnicks[i]).
you can replace the console.log() by your usual alert()
var arg = "pornoo";
var fnicks = ["porno","ibne","amcık","amcik","piç","salak","orospu","pkk","sik","kürdistan","kurdistan","kÜrdistan","kürt","sikeyim","sıkeyim","götoş","yönetici","YÖNETICI","YONETICI","yonetici","admın","admin","yarah","yarrah","agario","sike","s1ke","anan"];
var nctr = arg.toLowerCase();
for(var i=0,c=fnicks.length;i<c;i++) {
if(nctr.indexOf(fnicks[i]) > -1) {
console.log('boom');
}
}
I have some javascript that is fetching some JSON and I'm trying to combine certain rows of information together to use in a table.
The JSON looks like below:
[{"Code":"12345","Name":"foo","Service":"Payments"},
{"Code":"12345","Name":"foo","Service":"Marketing"},
{"Code":"23456","Name":"bar","Service":"Payments"},
{"Code":"23456","Name":"bar","Service":"Development"},
{"Code":"34567","Name":"baz","Service":"Marketing"}]
Basically some rows share the exact same information with each other except for one field, Service.
My thought was to try to turn each row into an object that I can either update or merge with another object that shares the same Code.
That object and code looks something like this:
function CustObj(code,name,hasPay,hasMarket,hasDev) {
this.code = code;
this.name = name;
this.hasPay = hasPay;
this.hasMarket = hasMarket;
this.hasDev = hasDev;
}
function formatData(data) {
var formatedData = [];
for (var key in data) {
var customer = new CustObj(data[key].Code,data[key].Name);
switch (data[key].Service) {
case 'Payments':
customer.hasPay = true;
break;
case 'Marketing':
customer.hasMarket = true;
break;
case 'Development':
customer.hasDev = true;
break;
}
formatedData.push(school);
}
}
The problem is that I want to have one object for each unique Code but that has the correct amount of flags based on Service but I haven't figured out how to do that yet. I was looking at doing something like $.extend(formatedData,customer) to merge objects but I can't seem to get the right logic for locating the two objects that I'm trying to merge.
Any thoughts on how this can be accomplished?
You can process the array for duplicates and create a new array where the "Service" property is an array of services that share the same Code and Name:
var data = [
{"Code":"12345","Name":"foo","Service":"Payments"},
{"Code":"12345","Name":"foo","Service":"Marketing"},
{"Code":"23456","Name":"bar","Service":"Payments"},
{"Code":"23456","Name":"bar","Service":"Development"},
{"Code":"34567","Name":"baz","Service":"Marketing"}
];
function mergeServices(data) {
var result = [], item, match, found;
// for each array item
for (var i = 0; i < data.length; i++) {
item = data[i];
found = false;
for (var j = 0; j < result.length; j++) {
// see if we have a dup of a previously existing item
if (item.Code == result[j].Code && item.Name == result[j].Name) {
// just add the Service name to the array of the previous item
result[j].Service.push(item.Service);
found = true;
break;
}
}
if (!found) {
// copy the current row (so we can change it without changing original)
var newItem = {};
for (var prop in item) {
newItem[prop] = item[prop];
}
// convert service to an array
newItem.Service = [newItem.Service];
result.push(newItem);
}
}
return result;
}
var output = mergeServices(data);
That produces this output:
[
{"Code":"12345","Name":"foo","Service":["Payments","Marketing"]},
{"Code":"23456","Name":"bar","Service":["Payments","Development"]},
{"Code":"34567","Name":"baz","Service":["Marketing"]}
]
Working jsFiddle: http://jsfiddle.net/jfriend00/6rU2z/
As you create your customers you can add them to a map (an object) so that they can be referenced by code. You only create customers that are not already in the map. For each row you get or create the corresponding customer and set the corresponding flag.
function formatData(data) {
var customerMap = {};
$(data).each(function(index, elem){
// Get the customer if it is already in the map, else create it
var customer = customerMap[elem.Code];
if(!customer) {
customer = new CustObj(elem.Code, elem.Name);
customerMap[elem.Code] = customer;
}
// Add flags as appropiate
switch (elem.Service) {
case 'Payments':
customer.hasPay = true;
break;
case 'Marketing':
customer.hasMarket = true;
break;
case 'Development':
customer.hasDev = true;
break;
}
});
// Convert map to array
var formatedData = [];
for(var code in customerMap){
formatedData.push(customerMap[code]);
}
}
function CustObj(code,name) {
this.code = code;
this.name = name;
this.hasPay = false;
this.hasMarket = false;
this.hasDev = false;
}
EDIT I've created a fiddle to demonstrate this
JSFiddle