dont wait until function finishes to run another function - javascript

Hello I am creating this script where I create a post request that adds an item to cart and selects the size all in the backend.
As it runs it opens up a loading html and I wanted to have the current item that is being added's info added into a table in the html page.
Im not sure if this is the most efficent and fast method (please let me know if there is a better way) but what I did was I create a listener on the html/js page and send a message from the background.js page that is doing the work to that js page that is listening for the message.
What it does is that It finds the item so it sends a message of the item name, then it finds the items proper color and sends a message of the color selected, then it finds the size and selects the proper size. here is the code:
chrome.runtime.sendMessage({ carting: true, status: {
status_item: (item[0]) //item name
} });
//carting code(irrelevant to this issue)
chrome.runtime.sendMessage({ carting: true, status: {
status_color: (item[1]) //item color
} });
//more irrelevent carting code
chrome.runtime.sendMessage({ carting: true, status: {
status_size: (size_text.text) // size
} });
this is what I had in the listener page:
chrome.runtime.onMessage.addListener(function(message, sender) {
if (!message.carting) return;
var Status = message.status;
$(function() {
$("#tasks_table").append('<tr>'
+'<td>'+item+'</td>'
+'<td>'+color+'</td>'
+'<td>'+size+'</td>'
+'</tr>');
}
})
The problem with it was is that during the carting process when it yet hasn't found the color it would just constantly add undefined into the table so I found a solution to that issue by using functions:
function waitForItem(item) {
if (typeof item !== "undefined") {
$("#tasks_table").append('<tr>'+'<td>'+item+'</td>');
} else {
setTimeout(waitForItem, 10);
}
}
function waitForColor(color) {
if (typeof color !== "undefined") {
$("#tasks_table").append('<td>'+color+'</td>');
} else {
setTimeout(waitForColor, 10);
}
}
function waitForSize(size) {
if (typeof size !== "undefined") {
$("#tasks_table").append('<td>'+size+'</td>'+'</tr>');
} else {
setTimeout(waitForSize, 10);
}
}
waitForItem(item);
waitForColor(color);
waitForSize(size);
Now this did work it stopped adding the undefined into the table but now the problem is that it runs the first item function until it is completly done and then so on with each function.
When I have two items it adds the item name for the first item into the table then waits until the second item name is found and adds it too then proceeds to add all the color and the sizes. The problem with this is that my background page works in a loop. It finds the first item, then its color, then its size, then it goes onto the next item, its color, and its size.
So when It finds the first item and then the second item it adds all the rest of the color and size right at the same time. Which I don't want.
I want it to add the info into the table the same way the background page runs so the user can see how smoothly and fast it runs.

Related

Suitescript: Popup when item is added on sales order

I want a popup to appear when certain items are added to a sales order in Netsuite. The popup shall appear on create and edit. In my code so far, I want the popup to appear when item number 5071, 1337 or 12345 is added to a sales order. But nothing happens when I've deployed the script. I have deployed it for all roles on the sales order record. I got the script from https://netsuiteprofessionals.com/question/popup-message-on-sales-order-when-certain-item-added/ but tweeked it a little bit.
Does anyone know what's wrong here? And how do I add so that the script logs each time it has shown a message?
/**
* #NApiVersion 2.0
* #NScriptType ClientScript
* #NModuleScope SameAccount
*/
define(['N/ui/dialog','N/record','N/currentRecord'],
function (dialog, record, currentRecord) {
function validateLine(context) {
var soRecord = context.currentRecord;
var list = context.sublistId === 'items';
var itemsArray = [507000, 124, 125];
var currentItem;
if (list) {
currentItem = soRecord.getCurrentSublistValue({
sublistId: 'items',
fieldId: 'item'
});
if (itemsArray.indexOf(currentItem) !== -1) {
dialog.alert({
title: 'Question?',
message: 'Please confirm this and that.'
}).then(success).catch(failure);
}
}
}
function success() {
return success;
}
function failure() {
return false;
}
return {
validateLine : validateLine
};
});
There is an arbitrary maximum of 10 client scripts supported. If your script is eleventh, or further down on the Client Scripts subtab of the Scripted Records page, it will not run. (This may depend whether the scripts above it are all deployed - I don't know every nuance of how the 10 are counted). You can change the order of scripts to ensure more important ones are run by Editing the Scripted Record page, selecting the line for the script you want to reorder and then drag the handle (6 dots at the left).
To work around the "10 script limit", you can refactor your client scripts to include more functionality in a single script. This can still be an issue if you have many bundles/SuiteApps installed with locked client scripts, but you can choose which ones to prioritize.
Another issue you have is here:
if (list) {
currentItem = soRecord.getCurrentSublistValue({
sublistId: 'items', //ON THIS LINE
fieldId: 'item'
});
if (itemsArray.indexOf(currentItem) !== -1) {
dialog.alert({
title: 'Question?',
message: 'Please confirm this and that.'
}).then(success).catch(failure);
}
}
Your alert function runs conditionally based on the currentItem being present. However, currentItem depends on a value being pulled from the items sublist, which does not exist. The correct sublist ID is item.

Coding custom Screen Navigation into Lightswitch HTML

I would like to have Button action event in LS HTML go slightly against the built-in navigation framework.
Specifically, to have LS navigate from one AddEditScreen to another AddEditScreen automatically, triggered by this Button event.
The trick is this - I need it to navigate to the AddEditScreen of the "next item up" in the Browse Screen List, without returning to the Browse Screen.
Example:
Select item 'ABC01' on a Browse Screen > Navigate to the AddEditScreen for 'ABC01' > edit 'ABC01' > when finished editing, trigger an event that will enable LS to navigate directly to the AddEditScreen for 'ABC02' from the Browse Screen list.
I have an open mind about what that event could be. A Button...anything at all.
I have created a Button and chose 'Write my own method'.
Does this look even close to code that will work, or will LS need to get the value of 'ABC01' from a query of some type?
myapp.AddEditHoldingInventory.Method_execute = function (screen) {
// Write code here.
var navigateToNextScreen = function (Method) {
return screen.getStrRqsNum().then(function (StrRqsNum) {
if (!!StrRqsNum) {
return myapp.applyChanges().then(function () {
var paramValue = (Number(StrRqsNum) += 1).toString();
return myapp.ShowAddEditHoldingInventory(id);
}
});
});
}
The code above is modified by me, and I am not a programmer or developer. It is snippets from pieces I have gathered and am trying to make sense of.
What the code is trying 'miserably' to achieve, is:
get the value of StrRqsNumber > save the edits made on the screen > add +1 to the value of StrRqsNumber > navigate to the AddEditSCreen of the record with the new value.
StrRqsNumber = a column with a value. It is unique and identifies an asset. This is most likely NOT the best way to achieve what I am trying to achieve, so I am here for advice. I don't have to use this as the parameter, as long as I can hit the 'next item up' from the list.
Thank you very much for any input. I will be SO stoked to get this behavior working.
This problem was solved by joshbooker. Here was the solution, which only needed minimal project specific tailoring...
"Question
Vote as helpful
0
Vote
What I want to achieve is this, for example:
Browse Screen > Select item 1 of 15 in the list > scan in the information we need on the AddEditScreen for item 1 > hit the 'trigger', and have LS automatically Save that edit, then navigate to the AddEditScreen of item 2 of 15 > and so on.
Here is a working solution for this:
/// <reference path="~/GeneratedArtifacts/viewModel.js" />
myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute = function (screen)
{///custom screen method to set selected item to next StrRqsNum
//calc next num
var nextNum = (Number(screen.HoldingInventories.selectedItem.StrRqsNum) + 1).toString();
// iterate collection data to find the next item
var nextItem = msls.iterate(screen.HoldingInventories.data)
.where(function (i)
{
return i.StrRqsNum == nextNum;
}).first();
if (nextItem)
{ //if found - select the item & return true
screen.HoldingInventories.selectedItem = nextItem;
return true;
}
else
{ //not found - return false
return false;
};
};
myapp.BrowseHoldingInventories.TapMethod_execute = function (screen) {
// tap method of list item on browse screen.
//handy way to save/set scroll position
var scrollTopPosition = $(window).scrollTop();
//currently selected item
var item = screen.HoldingInventories.selectedItem;
//showAddEditScreen - pass item
// beforeShown: setup binding on FieldB
//afterClosed: if commit & select next then recurse
myapp.showAddEditHoldingInventory(item, {
beforeShown: function (addEditScreen)
{//this executes before the screen is shown
//find the trigger field
var contentItem = addEditScreen.findContentItem("FieldB");
if (contentItem)
{ //databind to catch value change
contentItem.dataBind(contentItem.bindingPath, function(newValue){
if (newValue && contentItem.oldValue && newValue != contentItem.oldValue)
{ //if change then commit - this triggers close of addEditScreen
myapp.commitChanges();
}
contentItem.oldValue = newValue;
});
}
},
afterClosed: function (addEditScreen, navigationAction)
{//this executes after the screen is closed
//scroll browse screen to where we left off
$(window).scrollTop(scrollTopPosition);
//if commit
if (navigationAction == msls.NavigateBackAction.commit)
{ //try to select next item in list
if (myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute(screen) == true)
{ //next item selected then recurse
myapp.BrowseHoldingInventories.TapMethod_execute(screen);
}
}
}
});
};
"

Switching style between two elements on photo gallery change

So I have a photo gallery on my front page that switches between two images; each image links to a different page. Now, beside that gallery I have two links that go to the same two pages. The idea is that when image A is showing, side-link A should be highlighted with a border. The issue I keep running into is that once I get either side-link to be highlighted, I don't really know how to get it unhighlighted. Instead of switching with the images, they just stay highlighted.
var debugLink = "#firstLink";
function displayNextImage()
{
index++;
if(index >= indexgalpics.length)
{
index=0;
}
//---this is where I set the var debugLink which is
// supposed to carry the selected linke
if(index == 0)
{
console.log("first link selected");
//---when image A is showing, top side-link should be highlighted
//---ok so we know this much works, it seems these double equal
// signs are very important here.
//---makeActive();
//---but once makeActive() is called here, it makes the first link
// active for the entire time.
//---we can't put the entire style code here because same as before,
// it just keeps the link highlighted forever
debugLink = "#firstLink";
//---ok so i can set a var at top to a value in the makeActive() function,
// but i think the way JS works highlights either one forever
debugLink = "#firstLink";
}
else if(index == 1)
{
console.log("second link should be selected");
//---when image B is showing, bottom side-link should be highlighted
debugLink = "#secondLink";
}
showImg();
}
function makeActive()
{
var activeLink = document.querySelector(debugLink);
//---adds style to the debugLink
}
The function makeActive() is called in the function showImg(), and the function displayNextImage() is called in another function that sets the timer.
I changed your approach a little bit by using a boolean for the index, because you seem to only need two states.
Here is a revised version:
Note: In this code, I've used custom-made functions to make the code easier to read. I created hasClass(el,class), addClass(el,class), removeClass(el,class), toggleClass(el,class,bool). You can find them in the final JS Fiddle.
// Register the link elements
var links = {
true : document.getElementById('firstLink'),
false : document.getElementById('secondLink')
},
// Keep track of selected link (replaces your 'index')
leftLinkActive = false,
// Just so you don't go get it every time
gallery = document.getElementById('gallery');
// Let's trigger the gallery
displayNextImage();
// We'll change the active link and show the correct image
function displayNextImage(){
leftLinkActive = !leftLinkActive;
if(leftLinkActive){ console.log("first link selected"); }
else{ console.log("second link selected"); }
makeActive();
showImg();
// Let's do that again in 2 seconds
setTimeout(displayNextImage,2000);
}
// Add / remove the active class
function makeActive(){
addClass( links[ leftLinkActive ], 'active-class');
removeClass( links[ !leftLinkActive ], 'active-class');
}
// Change the image with a small fadeOut transition
function showImg(){
addClass(gallery,'fadeOut');
setTimeout(function(){
// Here we switch from img1 and img2
gallery.style.backgroundImage = 'url('+(leftLinkActive?'im1.jpg':'im2.jpg')+')';
removeClass(gallery,'fadeOut');
},200);
}
JS Fiddle Demo

adding class to array elements through loop

I need the loop that checks input fields from 'inputs' array, and if there are empty fields, special dialog need to be displayed near them, and after the dialog is displayed I need class 'style' to be added to the input field near which the dialog was displayed, then dialog should go to the next emppty field and add class 'style' to it. And so on until all empty inputs have class 'style'.
The problem is, in my loop after the dialog is displayed class 'style' is added only to the last element from the array, but it should be added to every empty element with delays in between.
This is my loop, but as I said it is not working properly:
for(i=0;i<inputs.length;i++){
var now = inputs[i];
var top = inputs[i].attr('top');
if(!now.val()){
if(dialog.css('display')=='none'){now.addClass('style');dialog.css('top',top).fadeIn(200);}
else{dialog.delay(300).animate({"top": top}, 500, function(){now.addClass('style');});
}else{now.removeClass('style');}}
P.S. Sorry for my English.
This is happening because the function that is calling 'addClass' is happening after the 300 millisecond animation. By that time, the value of the 'i' variable has changed because the for loop will continue to run.
You may just be able to have the 'now.addClass' call before the 'animate' and delay. Otherwise, you will have to break the loop and continue after the animation is complete to prevent the variable from being overwritten.
Here is an example of what I was talking about. The code below will process 1 input at a time and not continue to the next until the current one is finished processing (this code has not been tested):
var offset = -1;
var inputs = (something goes here)
iterateInputs();
function iterateInputs()
{
offset++;
if (typeof inputs[offset] != 'undefined')
{
eachInput();
}
else
{
// all done!
}
}
function eachInput()
{
var now = inputs[offset];
var top = inputs[offset].attr('top');
if (!now.val())
{
if (dialog.css('display')=='none')
{
now.addClass('style');
dialog.css('top', top).fadeIn(200, function(){
iterateInputs();
});
}
else
{
dialog.delay(300).animate({"top": top}, 500, function(){
now.addClass('style');
iterateInputs();
});
}
}
else
{
now.removeClass('style');
iterateInputs();
}
}

JQuery/Javascript works on & off

I am using JQuery 1.3.2-min in a project to handle JavaScript animations, ajax, etc. I have stored the file on the same server as the site instead of using Google. When I run the site locally on my development machine, everything works fine in FF, IE, Opera, and Safari (all the latest versions - I work from home and I only have 1 machine for personal use and development use) except for some CSS differences between them and when I go to the live site on my machine it works fine also. I have cleared my caches and hard refreshed the page, and it still works.
This is where it gets interesting however. When I send the site to my boss to test in various OS/Browser configurations, one page doesn't work correctly, some of it works, some doesn't. Also, the client (who uses IE 8) has also confirmed that it is not completely working - in fact he has told me that the page will work fine for a hour, and then just "turn off" for a while. I have never heard of this sort of thing before, and google isn't turning too much up. I have a hunch it may partly be with JQuery's .data(), but I'm not sure.
The page is basically nested unordered lists, and three basic actions happen on the list.
The top most unordered list is set to visible (all list via css are set to display: none to keep them hidden on a fresh page request); all list items divs are given a hover action of full opacity on mouseon, and faded back to 50% opacity on mouseoff; and then whenver a paragraph is clicked, the top most unordered list in that list item is displayed.
Here is my Javascript file for the page:
$(function() {
// Set first level ul visible
$('div#pageListing ul:first').css('display', 'block');
// Disable all the hyperlinks in the list
$('div#pageListing li a').click(function() {
var obj;
obj = $(this).parent(0).parent('div:first');
highlight(obj);
return false;
});
// List Item mouse hovering
$('#pageListing li').hover(
// Mouse On
function() {
if ($(this).children('div').attr('id') !== 'activePage') {
$(this).children('div').css('opacity', 1).css('filter',
'alpha(opacity=100)');
}
}, // Mouse off
function() {
if ($(this).children('div').attr('id') !== 'activePage') {
$(this).children('div').css('opacity', 0.4).css('filter',
'alpha(opacity=40)');
}
});
// Active list item highlighting
$('#pageListing li div').click(function() {
highlight($(this));
});
// Sub-list expanding/collapsing
$('#pageListing p.subpageslink').click(function() {
// Get next list
var subTree = $(this).parent('div').next('ul');
// If list is currently active, close it, else open it.
if (subTree.data('active') != true) {
subTree.data('active', true);
subTree.show(400);
} else {
subTree.data('active', false);
subTree.hide(400);
}
});
// Double clicking of list item - edit a page
$('#pageListing li div').dblclick(function() {
var classes = $(this).attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
editPage(pageID);
});
// Handle button clicking
$('button#addPage').click(function() {
addPage();
});
$('button#editPage').click(function() {
var div = $('div#activePage');
var classes = div.attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
editPage(pageID);
});
$('button#delPage').click(function() {
var div = $('div#activePage')
var classes = div.attr('class');
var classArray = classes.split(' ');
var pageID = classArray[1];
delPage(pageID);
});
});
// Highlighting of page when clicked
function highlight(obj) {
// Get previous hightlighted element
// and un-highlight
var oldElement = $('div#activePage');
oldElement.css('background', 'white');
oldElement.css('opacity', 0.4).css('filter', 'alpha(opacity=40)');
oldElement.removeAttr('id');
// highlight current selection
obj.attr('id', 'activePage');
obj.css('opacity', 1).css('filter', 'alpha(opacity=100)');
obj.css('background', '#9dc0f4');
// add appropiate action buttons
$('button.pageButton').css('display', 'inline');
}
function addPage() {
window.location = "index.php?rt=cms/editPage";
}
function delPage(page) {
var confirm = window.confirm("Are you sure? Any sub-pages WILL BE deleted also.");
if (confirm) {
var url = './components/cms/controller/forms/deletePage.php';
$.ajax( {
url : url,
type : 'GET',
data : 'id=' + page,
success : function(result) {
if (!result) {
document.location = "index.php?rt=cms";
} else {
window.alert('There was a problem deleting the page');
}
}
});
}
}
function editPage(page) {
var url = "index.php?rt=cms/editPage/" + page;
window.location = url;
}
Is it possible that you are linking to (some of) the script files using a src that points to a file on your local disk/HDD? If so, that would explain why it works only on your machine, as then only your machine has access to the script file.
Thank you one and all for your suggestions. The end problem was miscommunication. I work from home, and upload my projects to a SVN server, which the boss then uses to update the live server. Somehow, the correct files were not getting updated - a communication error on my part. Another possible reason was that the page, while being declared XHTML 1.0 Strict, had something like 50 validation errors (mosting incorrectly nested UL), and I cleaned that up to 5 errors. So thank you all, but again a sad example of the importance of team work communication.

Categories

Resources