Refreshing a variable when records deleted from localStorage - javascript

I have a localStorage object like this:
Key: jpxun
Value: [{"id":"0","name":"royal"},{"id":"1","name":"tippins"},{"id":"4","name":"leviosa"},{"id":"5","name":"vicious"}]
I have this JS to display the localStorage records:
// get localStorage info
var jpxun = JSON.parse(localStorage.getItem('jpxun')) || [];
// get localStorage length
if (jpxun) {
var jpxun_length = jpxun.length;
} else {
var jpxun_length = 0;
}
// assign variables for HTML ID elements
var list_items = document.getElementById("usernames");
var plaintext_textarea = document.getElementById("plaintext");
// assign a MyUsernames variable
var MyUsernames = JSON.parse(localStorage.getItem("jpxun"));
// if localStorage length > 0
if (jpxun_length > 0) {
// loop through localStorage
// get the word part of the username and wrap in list item HTML
// add a link in the list item to delete the localStorage ite via 'deleteById'
for (var i = 0; i < MyUsernames.length; i++) {
// assign a variable to hold the username
var un1 = MyUsernames[i].name;
list_items.innerHTML += "<li>" +"<a id="+MyUsernames[i].id + " href='#' onclick='deleteById(this)'>" + un1 + "</a></li>";
// build plaintext version of username list
plaintext_textarea.innerHTML += un1 + "\n";
}
}
// function to delete records from localStorage
var deleteById = function ( self ) {
MyUsernames = MyUsernames.filter(function(elem) {
return elem.id !== self.id;
});
localStorage.setItem("jpxun",JSON.stringify(MyUsernames));
self.parentNode.parentNode.removeChild(self.parentNode);
// try to re-do plaintext content
var jpxun2 = JSON.parse(localStorage.getItem('jpxun')) || [];
var MyUsernames2 = JSON.parse(localStorage.getItem("jpxun2"));
for (var i = 0; i < MyUsernames2.length; i++) {
var un1 = MyUsernames[i].name;
plaintext_textarea.innerHTML += un1 + "\n";
}
}
I realise that's a bit of code overload...
Basically it all works - the thing I can't get to work is that when I delete a record from localStorage, e.g. by clicking HTML for a list item for a word, which might look like this:
<li><a id="1" href="#" onclick="deleteById(this)">tippins</a></li>
Then the record is deleted from localStorage, and div id usernames containing the words as list items is automatically refreshed, as the deleted record is removed.
However, the list of words in the textarea is not refreshed (even though it is built up from the list of items in localStorage).
Here's what I tried to refresh the textarea list of words when a word is deleted from localStorage in the deleteById function:
// try to re-do plaintext content
var jpxun2 = JSON.parse(localStorage.getItem('jpxun')) || [];
var MyUsernames2 = JSON.parse(localStorage.getItem("jpxun2"));
for (var i = 0; i < MyUsernames2.length; i++) {
var un1 = MyUsernames2[i].name;
plaintext_textarea.innerHTML += un1 + "\n";
}
However - that doesn't work, and the textarea list is not updated and the deleted words still appear in that.
The only way the textarea list is updated is when the page reloads, but I'd like to have the list automatically update when a record is deleted from localStorage, in the same way the list items are automatically updated.

I'd simply create a function with a single responsibility to render the content of the textarea based on the data stored in the localStorage, like below
function renderTextArea() {
let data = JSON.parse(localStorage.getItem("jpxun")) || [];
let content = data.map(u => u.name).join("\n");
plaintext_textarea.innerHTML = content;
}
and then just call this function in your deleteById.

Related

Accessing variables from a parent function within a jQuery click() event (Word add-in)

The code for my add-in takes a search term, then displays a list of matching links on a table. Each link is supposed to insert itself into a word document when it's clicked, but I can't figure out how to pass variables in to a jQuery .click() function.
Currently, no matter what option I click, the URL of the link that gets inserted into the word document is always the URL of the last item on the list. So for example, if I had 3 results in the table: Facebook, Instagram and Yahoo, then whatever option I click, the URL that gets inserted is always http://www.yahoo.com
function displayLinks() {
// Empty pre-existing results
$('#linksTable').empty();
var filteredLinks = [];
// Grab value from search box
var searchTerm = document.getElementById('linksSearchField').value;
// Separate all links containing search term and put them in a filtered list
for (var i = 0; i < numberOfLinks; i++) {
if (sortedLinks[i].linkName.toLowerCase().includes(searchTerm.toLowerCase())){
filteredLinks.push(sortedLinks[i]);
}
}
// Get length of filtered links array
var numberOfSearchResults = filteredLinks.length;
// Populate table with loop
if (searchTerm != '') {
for (var x = 0; x < numberOfSearchResults; x++) {
var table = document.getElementById('linksTable');
var row = table.insertRow(x);
var nameCell = row.insertCell(0);
var linkName = filteredLinks[x].linkName;
var linkNameFormattedForID = linkName.replace(/([ &/!*^%$##+_-])+/g);
var linkURL = filteredLinks[x].linkURL;
// Add link to table
nameCell.innerHTML = "<a href='javascript:void(0);' id='" + linkNameFormattedForID + "'>" + linkName + "</a>";
// Code to add link to word document
$('#' + linkNameFormattedForID).click(linkName, function (linkName) {
Word.run(function (context) {
const doc = context.document;
const originalRange = doc.getSelection();
originalRange.insertHtml("<a href='" + linkURL + "'>" + linkName.currentTarget.innerText + "</a>", "Start");
originalRange.insertText("Refer to ", "Start");
originalRange.load("text");
return context.sync()
})
.catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
});
}
}
}
I think I could maybe fix the problem by defining the linkURL variable within the click function itself, but the issue is that I can't access filteredLinks[x] inside of it. I can access the filteredLinks array on its own, but it can't read x, even though the click function is contained within the loop?
As a last-resort super hacky fix, I think I could just change the ID of each item to include it's URL, then extract it from linkName.currentTarget.innerText, but I'd rather not do that unless I really have to.
Thanks in advance!
The problem is that var in JavaScript is function scoped, and because the click event gets invoked after the for loop ends, the value of x will always be the final value of x. There's more information in pleanty of blog posts like this one: https://medium.com/front-end-developers/es6-variable-scopes-in-loops-with-closure-9cde7a198744
The solution:
Use let or const instead of var
A slightly worse solution:
wrap the contents of the for loop inside an IIFE
for (var x = 0; x < numberOfSearchResults; x++) {
(function(x){
...
})(x);
}

RadComboBox custom text needs to have Outlook behavior

We have a customized Telerik RadComboBox that builds a text string of names separated by semicolons in the textbox field of the combobox by selecting names from the dropdown. We want to improve this and replicate a behavior similar to Outlook where individual names can be selected and deleted from the textbox. The selected names are stored in a hidden input field. Another hidden field carries a CSV list of IDs. Both hidden fields are treated like arrays, and their values have a one-to-one relationship by index. The approach we are considering is to wrap some kind of tag around each name, like a span, so that when a user selects a particular name the whole name will be highlighted and can then somehow be detected. Could this be done by using an ItemTemplate?
The OnClientSelectedIndexChanged event fires the javascript shown, and appends the list of names to the textbox.
function RecipientSelectedIndexChanged(sender, args) {
var combo = $find('<%= rcbRecipients.ClientID%>');
var userid = combo.get_selectedItem().get_value();
var name = combo.get_selectedItem()._text;
var listID = $get("<%= hdnRecipientIdList.ClientID%>").value;
var listName = $get("<%= hdnRecipientNameList.ClientID%>").value;
var listIDArray = new Array();
var listNameArray = new Array();
if (listID != '') {
listIDArray = listID.split(',');
listNameArray = listName.split('; ');
}
listNameArray.pop();
for (var i = 0; i < listNameArray.length; i++) {
listNameArray[i] = listNameArray[i] + '; ';
}
var x = listIDArray.indexOf(name);
if (x == -1) {
listIDArray.push(userid);
listNameArray.push(name + '; ');
listID = listIDArray.toString();
var y = listNameArray.join('');
listName = y;
}
$get("<%= hdnRecipientIdList.ClientID%>").value = listID;
$get("<%= hdnRecipientNameList.ClientID%>").value = listName;
combo.trackChanges();
var item = combo.findItemByText(name);
item.hide();
combo.set_text(listName);
combo.commitChanges();
combo.showDropDown();
}

How to iterate through javascript object and run a function on each value

I am new to JS.
I set up a Saved Search in NetSuite that gives us the image fields (containing URLs) of our items. I am now setting up a script in NS which tests these fields to see what item fields return 404 (i.e. need to be fixed).
My question is, how to set up function imageURLValidator to iterate through the field values of function searchItems?
Below is my start to the process but obviously has much incorrect syntax.
function imageURLValidator() {
var searchResults = searchItems('inventoryitem','customsearch529');
var url = '';
var item = '';
var field = '';
//insert loop here to iterate over items in searchResults array
//loop through items
for (var i = 0, i > searchResults[inventoryObject].length, i++) {
item = searchResults.[inventoryObject].[i];
//loop through fields in item
for (var f = 2, f > item.length, f++) {
field = item[f];
//check URL via item field's value
var code = checkURL(item[field].getvalue([field]));
//generate error based on code variable
createErrorRecord(code,item,field)
}
}
}
function searchItems(type, searchid) {
//defining some useful variables that we will use later
var inventoryArray = [];
var count = 0;
//loading the saved search, replace the id with the id of the search you would like to use
var inventoryItemSearch = nlapiLoadSearch(type, searchid);
//run the search
var inventoryItemResults = inventoryItemSearch.runSearch();
//returns a js array of the various columns specified in the saved search
var columns = inventoryItemResults.getColumns();
//use a do...while loop to iterate through all of the search results and read what we need into one single js object
do {
//remember the first time through the loop count starts at 0
var results = inventoryItemResults.getResults(count, count + 1000.0);
//we will now increment the count variable by the number of results, it is now no longer 0 but (assuming there are more than 1000 total results) will be 1000
count = count + results.length;
//now for each item row that we are on we will loop through the columns and copy them to the inventoryObject js object
for (var i=0; i<results.length; i++){
var inventoryObject = {};
for (var j=0; j<columns.length; j++){
inventoryObject[columns[j].getLabel()] = results[i].getValue(columns[j]);
}
//then we add the inventoryObject to the overall list of inventory items, called inventoryArray
inventoryArray.push(inventoryObject);
}
//we do all of this so long as the while condition is true. Here we are assuming that if the [number of results]/1000 has no remainder then there are no more results
} while (results.length != 0 && count != 0 && count % 1000 == 0);
return inventoryArray;
}
function checkURL(url) {
var response = nlapiRequestURL(url);
var code = response.getCode();
return code;
}
function createErrorRecord(code,item,field) {
if (code == 404){
//create error record
var errorRecord = nlapiCreateRecord('customrecord_item_url_error');
errorRecord.setFieldValue('custrecord_url_error_item', item);
errorRecord.setFieldValue('custrecord_url_error_image_field', field);
}
}
Here I can see searchResults variable will be empty while looping. As your call to searchItems function is async. Which will take some time to execute because I guess it will fetch data from API. By the time it returns value, your loop also would have bee executed. You can test this by putting an alert(searchResults.length) or console.log(searchResults.length). For that you need to use callback function
Also even if you get the results in searchResults. The loop you are doing is wrong. The array you will get is like [{},{},{}] i.e. array of objects.
To access you'll need
for (var i = 0, i > searchResults.length, i++) {
var inventoryObject = searchResults[i] // your inventoryObject
for(var key in inventoryObject){
item = inventoryObject[key]; // here you will get each item from inventoryObject
//loop through fields in item
for (var f = 2, f > item.length, f++) {
field = item[f];
//check URL via item field's value
var code = checkURL(item[field].getvalue([field]));
//generate error based on code variable
createErrorRecord(code,item,field)
}
}
}
And yes welcome to Javascript

How to stop innerHtml repeating itself over and over again in a table?

I have made an array with objects that get there info from three different user variables, however on one of these there are many sub variables that i don't want it to repeat itself every time the user presses the select button(which updates the table) instead i want it to just add onto (or take away) from the sections that it already has in the table. thanks(if you need the variable code let me know) I have been trying to solve thi for a while now! please help!!
//creating array
var gProducts = new Array();
var gTotalCost = 0;
// Adding Products to array gProducts
function addProduct
{
var product = new Object();
product.name = name;
product.cost = cost;
gProducts.push(product);
gTotalCost += parseInt(cost)
}
//Getting products from array, use of for in loop setting new table rows in blank var for each array item
function renderProducts()
{
var HTMLadd = ""
for (var i in gProducts)
{
if( gProducts[i].cost > 0){
HTMLadd = HTMLadd +
"<tr>"+
"<td class='tableSettings00' id=tableRow2 >" + gProducts[i].name +
"</td>"+
"<td class='tableSettings'>€<span id=tableRow2part2>" + gProducts[i].cost +
"</span></td>"+
"</tr>";
}
else
{
}
}
document.getElementById('tableRow').innerHTML = HTMLadd;
}
You're using a for in loop, when you probably wanted just a for loop.
Change this line to
for (var i in gProducts)
to
for (var i = 0; i < gProducts.length; i++)
With a for/in loop, the variable i will be an object, and not an integer.

Add values to the cookie using URL

I'm working on my webshop and since I dont want users to have to register to use the webshop, im using javascript cookies to hold the values the user has entered. But I want people who go to the webshop with a different url (for example: http://test.com/index.php?124&342), having 2 values in the cart, I made some functions to work on this. Here is the following code:
function getUrlVars() {
var variabelen = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
var urls = $.cookie($.cookie('cart')) || [];
for (var i = 0; i < variabelen.length; i++) {
urls.push(variabelen[i]);
}
}
if ($.cookie('cart')) {
var Orders = $.parseJSON($.cookie('cart'));
} else {
var Orders = new Array;
}
getUrlVars();
Where "orders" is the json array with the selected product-ID's. Now this is not working as I wanted to. It's not pushing the URL variables into the cart.
Okay UPDATE:
I succeed in pushing the URL variables in the cookie, but now the following problem accurs.
function UpdateTotals() {
ToAddHTML = '<h1>Cart</h1></br>';
console.log(Orders);
TotalPrice = 0;
for (var i = 0; i < Orders.length ; i++) {
var Result = SubMenuItems.filter(function(v) {
return v.submenu_id === Orders[i];
})[0];
TotalPrice += parseFloat(Result.price);
ToAddHTML += '<div class=orderd> <span class="order" Orders='+i+'> </span>'+'€'+zoekresultaat.price+' '+zoekresultaat.title+'</br></div><hr>';
}
The live website is on(nb. im using dutch description so the functions have different names):
Website
If I understand the problem correctly this should do the trick:
// Given: page.html?109&10
// -----------------------
// Split the query string on '&', after the '?' and push
// each value into the array 'Bestellingen'
// -----------------------
$.each(document.location.search.substr(1).split('&'),function(key,value){
Bestellingen.push(value);
});
You can replace your method haalUrlVars with the two lines above and you should find that items 109 & 10 are added to your list as though the were in the cookie when the page loaded.
Does that help?

Categories

Resources