Reference issue with Javascript - javascript

I have an array of objects cached on client side using JS array.
var scannerDictionary = new Array(); //Holds all scanners unmodified
var modifiedScannerDictionary = new Array(); //Holds all scanners with modified values
The properties of each object is set/changed using GUI and updated in the object. Each object contains list of InputParameters (array of Parameter class containing Name, Value and other members).
Please have a look on GUI.
Below is the code i used to render the controls -
function renderControls(scannerId) {
var currentScanner = modifiedScannerDictionary[scannerId];
//Render Input Parameters
$("#tblInputCriteria").find('tr:gt(5)').remove();
for(var i=0;i<currentScanner.InputParameters.length;i++) {
var propType = currentScanner.InputParameters[i].DataType;
var inParName = currentScanner.InputParameters[i].Name;
switch(propType) {
case 0: //Number
var eRow1 = $("#tblInputCriteria").find('#emptyNumRow').clone();
$(eRow1).removeClass('hidden').attr('id', 'Row_'+currentScanner.InputParameters[i].Name);
$(eRow1).appendTo($('#tblInputCriteria'));
var prop1 = $(eRow1).find('#InNumPropName');
$(prop1).attr('id', 'InNumPropName_'+currentScanner.InputParameters[i].Name);
var propName1 = currentScanner.InputParameters[i].Name;
$(prop1).html(propName1);
var propVal1 = $(eRow1).find('#InNumPropValue');
$(propVal1).attr('id', 'InNumPropValue_'+currentScanner.InputParameters[i].Name);
$(propVal1).val(currentScanner.InputParameters[i].Value);
$(propVal1).blur(function () {
if(!ValidateNumber(this, propName1)) {
alert('Value should be numeric in ' + propName1);
setTimeout(function() {$(propVal1).focus();}, 100);
}else {
UpdateData(currentScanner.Id, propName1, $(propVal1).val());
}
});
break;
case 1: //String
var eRow2 = $("#tblInputCriteria").find('#emptyStrRow').clone();
$(eRow2).removeClass('hidden').attr('id', 'Row_'+currentScanner.InputParameters[i].Name);
$(eRow2).appendTo($('#tblInputCriteria'));
var prop2 = $(eRow2).find('#InStrPropName');
$(prop2).attr('id', 'InStrPropName_'+currentScanner.InputParameters[i].Name);
var propName2 = currentScanner.InputParameters[i].Name;
$(prop2).html(propName2);
var propVal2 = $(eRow2).find('#InStrPropValue');
$(propVal2).attr('id', 'InStrPropValue_'+currentScanner.InputParameters[i].Name);
$(propVal2).val(currentScanner.InputParameters[i].Value);
$(propVal2).blur(function () {
UpdateData(currentScanner.Id, propName2, $(propVal2).val());
});
break;
case 2: //Boolean
var eRow3 = $("#tblInputCriteria").find('#emptyBoolRow').clone();
$(eRow3).removeClass('hidden').attr('id', 'Row_'+currentScanner.InputParameters[i].Name);
$(eRow3).appendTo($('#tblInputCriteria'));
var prop3 = $(eRow3).find('#InBoolPropName');
$(prop3).attr('id', 'InBoolPropName_'+currentScanner.InputParameters[i].Name);
var propName3 = currentScanner.InputParameters[i].Name;
$(prop3).html(propName3);
var propVal3 = $(eRow3).find('#InBoolPropValue');
$(propVal3).attr('id', 'InBoolPropValue_'+currentScanner.InputParameters[i].Name);
$(propVal3).val(currentScanner.InputParameters[i].Value);
$(propVal3).blur(function () {
UpdateData(currentScanner.Id, propName3, $(propVal3).val());
});
break;
}
}
}
PROBLEM:
The problem here is of the variables inside switch working as reference variable. So the UpdateData() function gets the last Name for similar type properties. i.e. if fields are of Number type then only the last property is updated by UpdateData() method.
Can anybody help me out solve this issue. Thanks for sharing your time and wisdom.

Try something like the following. Its a tad overkill, but will bind the values of the variables to the closures.
var fnOnBlur = (function(thePropName, thePropVal) {
return function () {
if(!ValidateNumber(this, thePropName)) {
alert('Value should be numeric in ' + thePropName);
setTimeout(function() {$(thePropVal).focus();}, 100);
}else {
UpdateData(currentScanner.Id, thePropName, $(thePropVal).val());
}
};
})(propName1, propVal1);
$(propVal1).blur( fnOnBlur );
The link that Felik King supplied has much more detailed discussion.

Related

How to overwrite a json object?

I have json object with a key named favorite, it has a value of true, when the button is pressed I want to overwrite the value of the favorite key to false and vica versa.
This is what`s inside the json object:
allPlaces: "[{"title":"Test1 ","description":"Test 2","category":"restaurant","favourite":false}]"
function favourite(element) {
var allPlaces = JSON.parse(localStorage.getItem("allPlaces"));
var placeIndex = element.getAttribute("data");
places = {allPlaces}
if (allPlaces["favourite"] == true) {
places.favourite[placeIndex] = false;
element.querySelector('ion-icon').setAttribute('name', 'star-outline');
} else {
console.log("working");
places.favourite[placeIndex] = true;
element.style.color = '#FFE234';
element.querySelector('ion-icon').setAttribute('name', 'star');
}
localStorage.setItem("allPlaces", JSON.stringify(places));
}
allPlaces is an array (in this case it has 1 item) so therefore in order to change the property of an object inside it you have to give it an index like so allPlaces[0].favorite = true
I added some code as a reference
const allPlaces = '[{"title":"Test1 ","description":"Test 2","category":"restaurant","favourite":false}]';
const places = JSON.parse(allPlaces);
places[0].favorite = true;
console.log(places[0]);

JavaScript - Issues recovering a map in an object after being saved in localStorage

I've been dealing with this for some time. I've a list of sections in which the user checks some checkboxes and that is sent to the server via AJAX. However, since the user can return to previous sections, I'm using some objects of mine to store some things the user has done (if he/she already finished working in that section, which checkboxes checked, etc). I'm doing this to not overload the database and only send new requests to store information if the user effectively changes a previous checkbox, not if he just starts clicking "Save" randomly. I'm using objects to see the sections of the page, and storing the previous state of the checkboxes in a Map. Here's my "supervisor":
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
var children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children().length;
for (var i = 0; i < children; i++) {
if (i % 2 == 0) {
var checkbox = $("#ContentPlaceHolder1_checkboxes_div_" + id).children()[i];
var idCheck = checkbox.id.split("_")[2];
this.selections.set(idCheck, false);
}
}
console.log("Length " + this.selections.size);
this.change = false;
}
The console.log gives me the expected output, so I assume my Map is created and initialized correctly. Since the session of the user can expire before he finishes his work, or he can close his browser by accident, I'm storing this object using local storage, so I can change the page accordingly to what he has done should anything happen. Here are my functions:
function setObj(id, supervisor) {
localStorage.setItem(id, JSON.stringify(supervisor));
}
function getObj(key) {
var supervisor = JSON.parse(localStorage.getItem(key));
return supervisor;
}
So, I'm trying to add to the record whenever an user clicks in a checkbox. And this is where the problem happens. Here's the function:
function checkboxClicked(idCbx) {
var idSection = $("#ContentPlaceHolder1_hdnActualField").val();
var supervisor = getObj(idSection);
console.log(typeof (supervisor)); //Returns object, everythings fine
console.log(typeof (supervisor.change)); //Returns boolean
supervisor.change = true;
var idCheck = idCbx.split("_")[2]; //I just want a part of the name
console.log(typeof(supervisor.selections)); //Prints object
console.log("Length " + supervisor.selections.size); //Undefined!
supervisor.selections.set(idCheck, true); //Error! Note: The true is just for testing purposes
setObj(idSection, supervisor);
}
What am I doing wrong? Thanks!
Please look at this example, I removed the jquery id discovery for clarity. You'll need to adapt this to meet your needs but it should get you mostly there.
const mapToJSON = (map) => [...map];
const mapFromJSON = (json) => new Map(json);
function Supervisor(id) {
this.id = id;
this.verif = null;
this.selections = new Map();
this.change = false;
this.selections.set('blah', 'hello');
}
Supervisor.from = function (data) {
const id = data.id;
const supervisor = new Supervisor(id);
supervisor.verif = data.verif;
supervisor.selections = new Map(data.selections);
return supervisor;
};
Supervisor.prototype.toJSON = function() {
return {
id: this.id,
verif: this.verif,
selections: mapToJSON(this.selections)
}
}
const expected = new Supervisor(1);
console.log(expected);
const json = JSON.stringify(expected);
const actual = Supervisor.from(JSON.parse(json));
console.log(actual);
If you cant use the spread operation in 'mapToJSON' you could loop and push.
const mapToJSON = (map) => {
const result = [];
for (let entry of map.entries()) {
result.push(entry);
}
return result;
}
Really the only thing id change is have the constructor do less, just accept values, assign with minimal fiddling, and have a factory query the dom and populate the constructor with values. Maybe something like fromDOM() or something. This will make Supervisor more flexible and easier to test.
function Supervisor(options) {
this.id = options.id;
this.verif = null;
this.selections = options.selections || new Map();
this.change = false;
}
Supervisor.fromDOM = function(id) {
const selections = new Map();
const children = $("#ContentPlaceHolder1_checkboxes_div_" + id).children();
for (var i = 0; i < children.length; i++) {
if (i % 2 == 0) {
var checkbox = children[i];
var idCheck = checkbox.id.split("_")[2];
selections.set(idCheck, false);
}
}
return new Supervisor({ id: id, selections: selections });
};
console.log(Supervisor.fromDOM(2));
You can keep going and have another method that tries to parse a Supervisor from localStorageand default to the dom based factory if the localStorage one returns null.

How to update JavaScript array dynamically

I have an empty javascript array(matrix) that I created to achieve refresh of divs. I created a function to dynamically put data in it. Then I created a function to update the Array (which I have issues).
The Data populated in the Array are data attributes that I put in a JSON file.
To better undertand, here are my data attributes which i put in json file:
var currentAge = $(this).data("age");
var currentDate = $(this).data("date");
var currentFullName = $(this).data("fullname");
var currentIDPerson = $(this).data("idPerson");
var currentGender = $(this).data("gender");
Creation of the array:
var arrayData = [];
Here is the function a created to initiate and addind element to the Array :
function initMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
var isFound = false;
// search if the unique index match the ID of the HTML one
for (var i = 0; i < arrayData.length; i++) {
if(arrayData[i].idPerson== p_currentIDPerson) {
isFound = true;
}
}
// If it doesn't exist we add elements
if(isFound == false) {
var tempArray = [
{
currentIDPerson: p_currentIDPerson,
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate, currentAge: p_currentAge
}
];
arrayData.push(tempArray);
}
}
The update function here is what I tried, but it doesn't work, maybe I'm not coding it the right way. If you can help please.
function updateMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
for (var i = 0; i < arguments.length; i++) {
for (var key in arguments[i]) {
arrayData[i] = arguments[i][key];
}
}
}
To understand the '$this' and elm: elm is the clickableDivs where I put click event:
(function( $ ) {
// Plugin to manage clickable divs
$.fn.infoClickable = function() {
this.each(function() {
var elm = $( this );
//Call init function
initMatrixRefresh(elm.attr("idPerson"), elm.data("gender"), elm.data("fullname"), elm.data("date"), elm.data("age"));
//call function update
updateMatrix("idTest", "Alarme", "none", "10-02-17 08:20", 10);
// Définition de l'evenement click
elm.on("click", function(){});
});
}
$('.clickableDiv').infoClickable();
}( jQuery ));
Thank you in advance
Well... I would recommend you to use an object in which each key is a person id for keeping this list, instead of an array. This way you can write cleaner code that achieves the same results but with improved performance. For example:
var myDataCollection = {};
function initMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
if (!myDataCollection[p_currentIDPerson]) {
myDataCollection[p_currentIDPerson] = {
currentIDPerson: p_currentIDPerson,
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate,
currentAge: p_currentAge
};
}
}
function updateMatrix(p_currentIDPerson, p_currentGender, p_currentFullName, p_currentDate, p_currentAge) {
if (myDataCollection[p_currentIDPerson]) {
myDataCollection[p_currentIDPerson] = {
currentGender: p_currentGender,
currentFullName: p_currentFullName,
currentDate: p_currentDate,
currentAge: p_currentAge
};
}
}
Depending on your business logic, you can remove the if statements and keep only one function that adds the object when there is no object with the specified id and updates the object when there is one.
I think the shape of the resulting matrix is different than you think. Specifically, the matrix after init looks like [ [ {id, ...} ] ]. Your update function isn't looping enough. It seems like you are trying to create a data structure for storing and updating a list of users. I would recommend a flat list or an object indexed by userID since thats your lookup.
var userStorage = {}
// add/update users
userStorage[id] = {id:u_id};
// list of users
var users = Object.keys(users);

jQuery TypeError:function not found error

I want to get some properties of one of my div via following code
(function ($) {
function StickyNotes() {
this.getProperties = function (note) {
var properties = {};
properties['top'] = note.position().top;
properties['from_center'] = this.calcFromCenter(note.position().left);
properties['width'] = note.find(".resize").width();
properties['height'] = note.find(".resize").height();
return properties;
}
this.saveBoardAndNotes = function (board_id, board_name) {
var noteList = new Array();
$(".optimal-sticky-notes-sticker-note").each(function(){
// Replace plain urls with links and improve html
var note = $(this);
content = note.find(".textarea").html();
noteID = note.attr("id");
properties = JSON.stringify(this.getProperties(note));
});
}
}
var StickyNotes = new StickyNotes();
jQuery(document).ready(function (e) {
$('#sticky-notes-add-board').click(function (e) {
if(confirm('Do you want to save previous board?')) {
var board_id = $('.optimal-sticky-notes-board:last').attr('id');
var board_name = $('.optimal-sticky-notes-board:last').text();
StickyNotes.saveBoardAndNotes(board_id, board_name);
}
})
});})(jQuery);
But I get following error..
TypeError: this.getProperties is not a function
I filtered all data like content and noteID. They are showing. But problem with this.getProperties. How can i solve the problem. Thanks in advance.
Inside each loop this points to current optimal-sticky-notes-sticker-note div. One of the several ways to reference correct scope is to use variable pointing to outer this:
this.saveBoardAndNotes = function (board_id, board_name) {
var noteList = new Array();
var self = this;
$(".optimal-sticky-notes-sticker-note").each(function(){
// Replace plain urls with links and improve html
var note = $(this);
content = note.find(".textarea").html();
noteID = note.attr("id");
properties = JSON.stringify(self.getProperties(note));
});
}

How to define "interface" in js

Good day.
My question is quite dumb, I guess, but I'm not familiar enough with the termins, to ask it properly (and to get an answer from Google).
So - please help...
Shortly - I'm trying to create some major class, which will be insanitated by instances, which will describe some methods, and some fields.
Major logick will be implemented in parent class.
So, lets say I have a parent
function CRUD_Grid_model(){
//Settings part
this.GridElement = "" ;
this.editModeFlagElement = "" ;
this.newRowElement = "";
//Save logicks all lies here.
this.commit = function (){
alert("PLEASE REDEFINE COMMIT FUNCTION IN YOUR CODE");
}
;
//Settings part
//Some more code.
}
And a way I'll use it
//Das modell
var JobberCRUD = new CRUD_Grid_model();
JobberCRUD.GridElement = $('#jobbers_dg');
JobberCRUD.editModeFlagElement = $('#jobbers_tb_edit');
JobberCRUD.newRowElement = {jobb_name:'Enter new unique name',jobb_status:'Y'};
JobberCRUD.commit = function (){
if (this.endEditing()){
var addrows = this.GridElement.datagrid('getChanges','inserted');
var remrows = this.GridElement.datagrid('getChanges','deleted');
var updrows = this.GridElement.datagrid('getChanges','updated');
console.log(addrows);
console.log(remrows);
console.log(updrows);
//Send changes?
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
//Commit changes at local level
this.GridElement.datagrid('acceptChanges');
}
};
And, what I'd like to do, is smoething like this
I want a parent.commit function to allow me to do this in child
JobberCRUD.commit = function (apdrows,updrows,remrows){
//Send changes?
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
};
So, I have no ideas what shoudl I do to achieve that. Please advice me with some tags, what it is at least :)
Thanks in advance.
There is not exactly what you need in JavaScript, but I would tend to use this pattern :
function CRUD_Grid_model() {
...
this.onCommit = null;
this.commit = function (){
if (this.endEditing()){
var addrows = this.GridElement.datagrid('getChanges','inserted');
var remrows = this.GridElement.datagrid('getChanges','deleted');
var updrows = this.GridElement.datagrid('getChanges','updated');
if(this.onCommit != null) this.onCommit(addrows,updrows,remrows);
this.GridElement.datagrid('acceptChanges');
}
}
...
}
var JobberCRUD = new CRUD_Grid_model();
JobberCRUD.onCommit = function(apdrows,updrows,remrows) {
alert("Got total of " +addrows.length + remrows.length + updrows.length + " rows changed.");
};
JobberCRUD.GridElement = ...
Javascript doesn't have a built in notion of interfaces. A javascript object effectively "implements an interface" by having all the needed methods defined, but there's no language "interface" construct
You could use "extends" like so:
Object.prototype.extends = function(clazz) {
var o = new clazz();
for (var f in o) {
if(f === "extends") {
continue;
}
this[f] = o[f];
}
this.super = o;
}
Now could type something like this:
var JobberCRUD = function() {
this.extends(CRUD_Grid_model);
var privateFunction = function() {
//...
}
// You probably don't want to do that,
// but you could override
this.commit = function() {
//...
}
// ...
}
Hope, that helps.
Edit: forgot, that you may call super.commit() then.
You can not have something similar like C# or Java interface or even class with Javascript.
Javascript is just a dynamic scripting language.

Categories

Resources