Can get some values in JSON by key, others I cannot get - javascript

I have some JSON:
[{
"cityid":101,
"city":"Alta"
},
{
"cityid":102,
"city":"Bluffdale"
},
{
"cityid":105,
"city":"Draper"
},
{
"cityid":107,
"city":"Holladay"
}]
I can successfully search this array, and get the "city" value, with this function:
function getLocality(cid){
var storedlist = localStorage.getItem("citylist");
var clist = JSON.parse(storedlist);
for(var i = 0; i < clist.length; i++)
{
if(clist[i].cityid == cid) {
return clist[i].city;
} else {
}
}
}
My Issue:
When I try to use another function to get the city, instead of getting the cityid, it does not work.
The function I am using to try and get the city id, is as follows:
function getCityid(cid){
var storedlist = localStorage.getItem("citylist");
var clist = JSON.parse(storedlist);
for(var i = 0; i < clist.length; i++)
{
if(clist[i].city == cid) {
return clist[i].cityid;
} else {
}
}
}
I am calling the function as so:
getCityid('Draper');

I just opened up the console and tried both of your functions and they both seem to work. Since you didn't provide any sample input/output of your issue, I'll recommend the following:
Verify that you're passing in correct parameters into each function. The getLocality() should take in a cityid and getCityid() should take in a city.
Refrain from using == in javascript as this operator performs type coercion wherein things which are disparate types are "forced" to be the same type in order to perform comparison. You should instead use the === operator which will not perform type coercion. If the two things being compared are different types, it will simply evaluate to false.

Try this.
function getCityid(city) {
var storedlist = localStorage.getItem("citylist");
var clist = JSON.parse(storedlist);
for(var i = 0; i < clist.length; i++){
if(clist[i].city === city) {
return clist[i].cityid;
}
}
}

Related

Iterating over a nodelist, getting the length of a value of a node item

I am trying to dynamically grab ZIPcodes and validate them when the length is 5.
I used querySelectorAll to grab the Zipcode fields on the page, as well as a few other fields I will use after validating.
I iterate over the nodelist and pass it to another function, where the eventlistener kicks off if the value is the correct length.
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
if (zipId[i].length = 5)
AssortedZipCodeFunctions(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
}
function AssortedZipCodeFunctions(zipId, countyId, stateId, phoneId) {
//Runs auto-county/state function only when zipcode field is completed
document.addEventListener("keyup", (e) => {
if (zipId.value.length == 5) {
GetCountyAndStateFromIds(zipId, countyId, stateId, phoneId);
} });
}
The code works perfectly for me as it is listed above; I am just trying to move the second function into the first function, but I can't figure out how. I am just stuck on how come I can't do the following:
function GetZipCodeDetails() {
var zipId = document.querySelectorAll("[id*='ZipCode']");
var countyId = document.querySelectorAll("[id*='CountyId']");
var stateId = document.querySelectorAll("[id*='StateId']");
var phoneId = document.querySelectorAll("[id*='PhoneNumber']");
for (var i = 0; i < zipId.length; i++) {
document.addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}
}
The above gives: "TypeError: Cannot read property 'value' of undefined
at HTMLDocument."
I have figured out that the for loop is calling the second function, instead of waiting until the Zipcode value is 5... so all that happened is I passed it to another function? Or maybe I am stuck on how to get the length of the value of a node item? Please help.
In your event listener you are adding it to the document instead of each element separately
for (var i = 0; i < zipId.length; i++) {
zipId[I].addEventListener("keyup", (e) => {
if (zipId[i].value.length == 5) {
GetCountyAndStateFromIds(zipId[i], countyId[i], stateId[i], phoneId[i]);
}
});
}

Determine Type of Kendo UI Control

I have the following utility function that works (obviously it only looks for 5 types of controls, but that's all I use):
util.getKendoControlType = function(controlId) {
let controlTypes = ['kendoAutoComplete','kendoMultiSelect','kendoDatePicker','kendoDropDownList','kendoNumericTextBox'];
for(let i = 0; i < controlTypes.length; i++) {
let control = $('#' + controlId).data(controlTypes[i]);
if (typeof(control) !== 'undefined' && control !== null) {
return controlTypes[i];
}
}
return null;
};
My question: is this the only way to get the control type of a Kendo UI control, or is there a better way?
(Note: I'm aware that instead of returning null, I could also throw an error.)
Sure! Use kendo.widgetInstance:
util.getKendoControlType = function(controlId) {
return kendo.widgetInstance($(`#${controlId}`)).options.name;
}
You can also get the role data attribute:
util.getKendoControlType = function(controlId) {
return $(`#${controlId}`).data('role');
}

Mixing Index Array with "Associative Array"

Since I need to access my items sometime by index and sometime by code. Is it a good idea to mix integer index with string index?
Note that the code, index, amount of items never changes after the data is loaded.
I'm thinking of doing something like this, where the same object is pushed and set as a hashtable.
function DataInformation(code, dataValue) {
this.code = code;
this.dataValue = dataValue;
}
var dataList = [];
function fillDataList() {
addNewData(new DataInformation("C1", 111));
addNewData(new DataInformation("C2", 222));
addNewData(new DataInformation("C3", 333));
}
function addNewData(newData) {
dataList.push(newData);
dataList[newData.code] = newData;
}
Then I would be able to access the object with either:
dataList[0].dataValue
dataList["C1"].dataValue
Before I used to loop to find the item.
function findItemByCode(code) {
for (var i = 0; i < dataList.length; i++) {
if (dataList[i].code == code) {
return dataList[i];
}
}
return null;
}
findItemByCode("C1").dataValue
Do you ever need to iterate dataList in strict order? Or is it just a bag of items for which you want random access by a certain key?
If ordered iteration is not a concern, use an object instead of an array. Watch out for key clashes, though.
var dataList = {};
function addNewData(newData) {
dataList[newData.code] = newData;
dataList[newData.dataValue] = newData;
}
// that's it, no other changes necessary
If key clashes can occur - or ordered iteration is necessary, or if you just want to make it particularly clean, use an array and an accompanying index object.
var dataList = [];
var dataIndex = {
byCode: {},
byValue: {}
};
function addNewData(newData) {
dataList.push(newData);
dataIndex.byCode[newData.code] = newData;
dataIndex.byValue[newData.dataValue] = newData;
}
Here is my try using Proxies
// Code goes here
function DataInformation(code, dataValue) {
this.code = code;
this.dataValue = dataValue;
}
var _dataList = [];
var dataList = new Proxy(_dataList, {
get: function(target, name) {
if (target && target.myMap && target.myMap[name]) return target[target.myMap[name]];
return target[name];
},
set: function(obj, prop, value) {
// The default behavior to store the value
obj.myMap = obj.myMap || {};
obj.myMap[value.code] = prop;
obj[prop] = value;
return true;
}
});
function fillDataList() {
addNewData(new DataInformation("C1", 111));
addNewData(new DataInformation("C2", 222));
addNewData(new DataInformation("C3", 333));
}
function addNewData(newData) {
dataList.push(newData);
}
fillDataList();
console.log(dataList[0].dataValue);
console.log(dataList["C1"].dataValue);

Pull specific field from nth index of Knockout observableArray of objects

I have a page that displays a list of file templates built using the following method.
var loadCustomTemplate = function () {
loadBaseTemplate();
var res = 0;
for (i = 0; i < self.GetSeam().length; i++) {
var a = self.count() + 1;
self.count(a);
res = self.GetSeam()[i].FileFormat.split("_");
if (res.length == 4) {
var ap = res[3].split('.');
self.append(ap[0]);
} else {
self.append("");
}
var obj = {
Code: ko.observable(self.code()),
Number: ko.observable(self.number()),
SeamReportPath: ko.observable(self.reportPath()),
FileFormat: ko.observable(self.append()),
SequenceNumber: ko.observable(a)
}
self.CustomTemplate.push(obj);
}
self.count(0);
};
The user is then allowed to edit the fields as needed. They can also add records or remove them as needed. The method to add a record is as follows.
self.addTemplate = function () {
var count = self.CustomTemplate().length + 1;
var obj = {
Code: ko.observable(self.code()),
Number: ko.observable(self.number()),
SeamReportPath: ko.observable(self.reportPath()),
FileFormat: ko.observable(""),
SequenceNumber: ko.observable(count)
}
self.CustomTemplate.push(obj)
};
Once those updates are made they can save the updated CustomTemplate. This uses ajax that is not important to this question. The save method calls a validation method that is supposed to check to make sure there are no duplicate FileFormat fields in the object array. This is what I have, but it is failing.
var validateTemplates = function() {
for (i = 0; i < self.CustomTemplate().length; i++) {
var checkVal = self.CustomTemplate()[i].FileFormat;
var checkSeq = self.CustomTemplate()[i].SequenceNumber;
for (j = 0; j < self.CustomTemplate().length; j++) {
if (checkSeq !== self.CustomTemplate()[j].SequenceNumber ){
if (checkVal+"" === self.CustomTemplate()[j].FileFormat) {
if (checkSeq == self.CustomTemplate()[j].SequenceNumber ){
return false;
}
}
}
}
return true;
};
The problem is that when checking self.CustomTemplate()[i].FileFormat and self.CustomTemplate()[i].SequenceNumber it isn't reflecting the data displaying on the page or the data being sent to the controller (MVC 4). If I put either of those in an alert it is showing a function. How do I access the data in those specific fields for comparison?
Thanks in advance.
If I put either of those in an alert it is showing a function.
That's because you're doing this kind of thing:
var checkVal = self.CustomTemplate()[i].FileFormat;
FileFormat is the result of ko.observable(...), which returns a function, so checkVal in fact does contain a function.
The solution is for all those cases to do this:
var checkVal = self.CustomTemplate()[i].FileFormat(); // Parentheses at the end!
The parentheses execute the observable function, and if you do so without parameters you "get" the value of that observable. (If you would pass in a value, it would "set" the observable to that value.)

getting a key out of a javascript hash

I'm working with the latest draft of the twitter annotations api. An example bit of data looks like
status {
annotations : [
{myAnnotationType:{myKey:myValue}},
{someoneElsesAnnotationType:{theirKey:theirValue}},
]
}
now i want to check a status to see if it has an annotation with myAnnotationType in it. If annotations was a hash instead of an array I could just write var ann = status.annotations.myAnnotationType. But its not so I wrote this instead:
function getKeys(obj){
var keys = [];
for (key in obj) {
if (obj.hasOwnProperty(key)) { keys[keys.length] = key; }
}
return keys;
}
function getAnnotation(status, type){
for(var i=0;i<status.annotations.length;i++){
var keys = getKeys(status.annotations[i]);
for(var j=0;j<keys.length;j++){
if(keys[j] == type){
return status.annotations[i];
}
}
}
}
var ann = getAnnotation(status, "myAnnotationType");
There must be a better way! Is there?
PS I can't use jquery or anything as this is js to be used in a caja widget and the container doesn't support external libs
If I understand the purpose of this function correctly, you are trying to return the first object in an array (status.annotations) that contains a key (type)
function getAnnotation(status, type){
for (var i=0; i<status.annotations.length ; i++) {
var obj = status.annotations[i];
if (obj.hasOwnProperty(type)) return obj;
}
}
Ah man, jQuery would make it easy if you could be sure they'd never collide:
var annotations = $.extend.apply($, status['annotations'] || []);
var annotation = annotations['myAnnotationType'];
I guess you could write your own budget extend:
function collapse(annotations) {
var result = {};
for (var i = 0; i < annotations.length; i++) {
var annotation = annotations[i];
for (var key in annotation) {
if (annotation.hasOwnProperty(key)) {
result[key] = annotation[key]; // Using a deep cloning function possible here
}
}
}
return result;
}
Or you could have a hack at adapting jQuery's extend.

Categories