setRedirectURLToSearchResults() not redirecting - netsuite

I an new to NetSuite, and I am having a problem. I have created a button on a form through a user event script.
The button calls a client script, which executes a saved search. The search result should be displayed to the user.
Everything is located in one file:
function userEventBeforeLoad_AddSearchButton(type, form, request){
if(type == 'view' || type == 'edit'){
form.setScript('customscript_tvg_project_search_button');
var projectid = nlapiGetFieldValue('companyname');
form.addButton("custpage_search", "KHM Search", "performSearch('" + projectid + "')");
}
}
function performSearch(projectid) {
console.log('test in client');
alert('projectid = ' + projectid);
var obj = nlapiLoadSearch(null, 'customsearch_project_cost_detail_sublist');
obj.setRedirectURLToSearchResults();
}
I created a user event script record for userEventBeforeLoad_AddSearchButton(). and a client script record for performSearch().
In the code above, the button is created and the alert is being displayed. But no redirect is happening.
When I look at the result in Firebug it looks like this:
{"result":"\/app\/common\/search\/searchresults.nl?api=T","id":5}
Any ideas why the redirect is not happening, and what to do?
Edit: My code above was stripped down to simplify. The reason I am passing projectid over is that I actually need to filter the search result, suing the following two lines:
var searchFilter = new nlobjSearchFilter('job', null, 'anyof', projectid);
obj.addFilter(searchFilter)

Although the documentation does state that, "This method is supported in afterSubmit user event scripts, Suitelets, and client scripts", it seems from this NS User Group post by a Netsuite Employee in reply to someone who experienced the same issue as you, that the API does not actually perform the redirection client side:
Redirection works on server side. Use window.location.assign(url) to
navigate via script in client-side.
Testing this, I can see that setRedirectURLToSearchResults does appear to correctly "load the search into the session", so adding this line afterwards should fix your problem.
window.location = '/app/common/search/searchresults.nl?api=T';

setRedirectURLToSearchResults is not working for me either, but since you are using clientscript you might want to try this:
function performSearch(projectid) {
console.log('test in client');
alert('projectid = ' + projectid);
var searchid = 'customsearch_project_cost_detail_sublist';
location = '/app/common/search/searchresults.nl?searchid=' + searchid;
}

Related

How to troubleshoot 'Invalid Page Parameter' error in Netsuite

I'm still relatively new to NetSuite, and have taken over a project that a contractor did for us, so this may be a simple question. We have a Suitelet that is calling another Suitelet with nlapiRequestURL. The Suitelet that is being called, is supposed to return a single ID. Instead, we get a 'Invalid Page Parameter' response.
I looked at the configuration for the Suitelet that is called, and there is a parameter setup, but the 'Preference' field on that parameter is blank, which according to the documentation suggests that when that is the case, the parameter value should be defined in the Deployment, on the Parameter tab. Which it is, and appears to be the correct value.
So I assume the issue is with one of the parameters in the URL that is being used in nlapiRequestURL, and not the parameter defined on the script record in Netsuite. Here is an example of one of those URLs. I just changed the compid for obvious reasons:
https://forms.sandbox.netsuite.com/app/site/hosting/scriptlet.nl?script=147&deploy=1&compid=12345&h=e06792b0e7727d53f816&internalIds=17509
I verified that '147' is the correct script id. I also tried removing each of the parameters one by one from the URL, but that doesn't work. Depending on which one I remove, I either get 'An unexpected error occurred', or 'Missing a required parameter'. The only parameter that is being used inside the Suitelet that is called is 'internalids'. I can see that it's being obtained with 'request.getParameter("internalIds")'. (See code below)
As a sidenote, I'm not sure what the 'h' parameter is for in the URL, and can't find where that, or compid, or deploy is configured. I'm wondering if that 'h' value is incorrect, but am not sure what it's for. Why are 'compid', 'deploy' and 'h' being included in the URL? I can assume the compid is for identifying our company, but I'm not seeing how someone can determine how to build a URL for a request, since I don't know what mandatory parameters there are like that. I'm guessing I don't know where to look in Netsuite to find that configuration. Are there settings for base URLs somewhere?
Anyway, this is the script below that is being called. The other script is quite a bit longer, and has some company related info, so I'm not going to include it, but I don't think that matters anyway. The only thing that needs to be known is that we're using the URL above with nlapiRequestURL to call the script below, and calling 'getBody' on the result.
function suitelet(request, response){
nlapiLogExecution('DEBUG', 'suitelet', 'In the Preview_Link.suitelet function');
nlapiLogExecution('DEBUG', 'suitelet', 'The request is ' + JSON.stringify(request));
nlapiLogExecution('DEBUG', 'suitelet', 'The response is ' + JSON.stringify(response));
var context = nlapiGetContext();
var folderInternalId = context.getSetting('SCRIPT', 'custscript_buffer_folder_for_temp_pdf');
var strInternalIds = request.getParameter('internalIds');
if(!strInternalIds)
return;
var internalIds = strInternalIds.split(',');
if(!internalIds || internalIds.length == 0)
return;
var xml = "<?xml version=\"1.0\"?>\n<!DOCTYPE pdf PUBLIC \"-//big.faceless.org//report\" \"report-1.1.dtd\">\n";
xml += "<pdfset>";
for (var index = 0; index < internalIds.length; index++)
{
var internalId = internalIds[index];
xml += "<pdf src='"+ nlapiEscapeXML(nlapiLoadFile(internalId).getURL()) +"'/>";
}
xml += "</pdfset>";
var file = nlapiXMLToPDF(xml);
file.setName(internalIds[0] + '_' + internalIds.length + '_' + Math.random() +'.pdf');
file.setFolder(folderInternalId);
file.setIsOnline(true);
var internalIDUpdatedData = nlapiSubmitFile(file);
response.writeLine(internalIDUpdatedData);
}
So 'custscript_buffer_folder_for_temp_pdf' is the parameter defined on the Script record in Netsuite, and there is a value for it on that script's Deployment tab, on the Parameter tab, of '36', which is the value we want. That's our 'TEMP' folder in the File Cabinet. 'internalIds' is defined in the script that calls the one above, and it's either a single integer, or a comma separated list of them. (although it seems to always be a single value)
I should mention that this works in our production instance, and we just refreshed our Sandbox instance two days ago based on production. It didn't work in Sandbox prior to the refresh either. The only difference I can see, is that in production, the domain name is different in the URL, which of course it must be. All the code and settings appear to be identical besides that between the two environments.
Like I said, I'm new to Netsuite, so I haven't used nlapiRequestURL before. So this may be something incredibly stupid I'm overlooking. I've stepped through the code in the script that does the calling, but I can't seem to debug the Suitelet that is being called with nlapiRequestURL. I placed a nlapiLogExecution call as the first line in the script that is being called though, and it never even seems to hit that. I just get one of the errors I mentioned above before it actually steps into that script.
If anyone has any advice, I'd appreciate it. I've more or less exhausted my knowledge and resources. Thanks in advance, and let me know if you need further info.
Some things you may want to try:
var baseSuiteletURL = nlapiResolveURL('SUITELET', SUITELET_SCRIPT_ID, SUITELET_DEPLOYMENT_ID, true); //Getting URL from script id and deployment id
var reqUrl = baseSuiteletURL + "&internalids=17509"; //Adding your GET parameter here (all in lowercase)
var requestBody = {}; //Alternatively you could send your parameters within the POST body
requestBody.internalids = 17509;
var reqBody = JSON.stringify(requestBody);
var reqHeaders = {};
reqHeaders["User-Agent"] = "Mozilla/5.0"; //Sending user agent header to allow Suitelet to Suitelet calls
var myResponse = nlapiRequestURL(reqUrl, reqBody, reqHeaders);
Test sending your GET Query parameters (internalids) all in lowercase, I have experienced issues before in which the parameters case gets converted and it creates unnecessary troubles.

Calling an XAgent from a traditional Domino web app via AJAX

I have an XAgent I have created that works just fine via window.location but I can't get it to work via AJAX. This agent is called from a delete button on a popup div, so rather than writing to my responseStream in my XAgent, I'd prefer to just run my agent and close my popup via javascript when it is finished.
My XAgent is called by the URL doc.$DBPath.value + "/xAgent_DeleteDemand.xsp?open&id=" + doc.$DocUNID.value and looks like this:
javascript:importPackage(foo);
try {
var url:java.lang.String = context.getUrl().toString();
print(url);
if (param.containsKey("id")) {
var unid = param.get("id");
} else {
throw "No unid given";
}
XAgent.deleteDemand(unid);
} catch (e) {
print(e);
}
My actual code is in the foo package but that doesn't seem relevant because I'm not even getting my URL printed. I can say the the URL being generated and called works just fine using window.location so it is safe to assume that the problem is elsewhere.
I have a sneaking suspicion that maybe context doesn't have any meaning when called via AJAX from a non XPage app, but I don't know for sure.
I don't think there is anything special about my AJAX code but here it is just in case. It has been working fine for a long time.
function createAJAXRequest(retrievalURL, responseFunction) {
if (window.ActiveXObject) {
AJAXReq = new ActiveXObject("Microsoft.XMLHTTP");
} else if (window.XMLHttpRequest) {
AJAXReq = new XMLHttpRequest();
}
showHideIndicator("block")
var currentTime = new Date()
AJAXReq.open("GET", retrievalURL + "&z=" + currentTime.getTime());
AJAXReq.onreadystatechange = eval(responseFunction);
AJAXReq.send(null);
}
I'm not sure what the immediate problem would be, but as some troubleshooting steps:
The resultant URL is just server-relative and not on a different server+protocol combination, right?
Do you see anything on the browser's debug console when clicking the button?
Is there an entry in the browser's debug Network panel for the request at all?

data from web scraping using node.js request is different from data shown in the browser

Right now, I am doing some simple web scraping, for example get the current train arrival/departure information for one railway station. Here is the example link, http://www.thetrainline.com/Live/arrivals/chester, from this link you can visit the current arrival trains in the chester station.
I am using the node.js request module to do some simple web scraping,
app.get('/railway/arrival', function (req, res, next) {
console.log("/railway/arrival/ "+req.query["city"]);
var city = req.query["city"];
if(typeof city == undefined || city == undefined) { console.log("if it undefined"); city ="liverpool-james-street";}
getRailwayArrival(city,
function(err,data){
res.send(data);
}
);
});
function getRailwayArrival(station,callback){
request({
uri: "http://www.thetrainline.com/Live/arrivals/"+station,
}, function(error, response, body) {
var $ = cheerio.load(body);
var a = new Array();
$(".results-contents li a").each(function() {
var link = $(this);
//var href = link.attr("href");
var due = $(this).find('.due').text().replace(/(\r\n|\n|\r|\t)/gm,"");
var destination = $(this).find('.destination').text().replace(/(\r\n|\n|\r|\t)/gm,"");
var on_time = $(this).find('.on-time-yes .on-time').text().replace(/(\r\n|\n|\r|\t)/gm,"");
if(on_time == undefined) var on_time_no = $(this).find('.on-time-no').text().replace(/(\r\n|\n|\r|\t)/gm,"");
var platform = $(this).find('.platform').text().replace(/(\r\n|\n|\r|\t)/gm,"");
var obj = new Object();
obj.due = due;obj.destination = destination; obj.on_time = on_time; obj.platform = platform;
a.push(obj);
console.log("arrival ".green+due+" "+destination+" "+on_time+" "+platform+" "+on_time_no);
});
console.log("get station data "+a.length +" "+ $(".updated-time").text());
callback(null,a);
});
}
The code works by giving me a list of data, however these data are different from the data seen in the browser, though the data come from the same url. I don't know why it is like that. is it because that their server can distinguish the requests sent from server and browser, that if the request is from server, so they sent me the wrong data. How can I overcome this problem ?
thanks in advance.
They must have stored session per click event. Means if u visit that page first time, it will store session and validate that session for next action you perform. Say, u select some value from drop down list. for that click again new value of session is generated that will load data for ur selected combobox value. then u click on show list then that previous session value is validated and you get accurate data.
Now see, if you not catch that session value programatically and not pass as parameter with that request, you will get default loaded data or not get any thing. So, its chalenging for you to chatch that data.Use firebug for help.
Another issue here could be that the generated content occurs through JavaScript run on your machine. jsdom is a module which will provide such content but is not as lightweight.
Cheerio does not execute these scripts and as a result content may not be visible (as you're experiencing). This is an article I read a while back and caused me to have the same discovery, just open the article and search for "jsdom is more powerful" for a quick answer:
http://encosia.com/cheerio-faster-windows-friendly-alternative-jsdom/

Chrome Omnibox extension to post form data to a website?

How can an Omnibox extension create and post form data to a website and then display the result?
Here's an example of what I want to do. When you type lookup bieber into the Omnibox, I want my extension to post form data looking like
searchtype: all
searchterm: bieber
searchcount: 20
to the URL http://lookup.com/search
So that the browser will end up loading http://lookup.com/search with the results of the search.
This would be trivial if I could send the data in a GET, but lookup.com expects an HTTP POST. The only way I can think of is to inject a form into the current page and then submit it, but (a) that only works if there is a current page, and (b) it doesn't seem to work anyway (maybe permissions need to be set).
Before going off down that route, I figured that somebody else must at least have tried to do this before. Have you?
You could do this by using the omnibox api:
chrome.omnibox.onInputChanged.addListener(
function(text, suggest) {
doYourLogic...
});
Once you have you extension 'activated' due to a certain keyword you typed you can call something like this:
var q = the params you wish to pass
var url = "http://yourSite.com";
var req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onreadystatechange = function() {
if (req.readyState == 4) {
callback(req.responseXML);
}
}
req.send(q);

follow a link without using window.location

I hope you are all well!
A question for an app that uses Backbone.js and node.js.
I'm in a situation where I want to create a model, and then automatically go to a different uri that is constructed using the newly created model :
MessageView = Backbone.View.extend({
events : {
'click #button' : 'go here'
}
go here : function(model) {
var message = new Message({model : model)};
var id = message.get('id');
// go to uri '/messages/id'
Now I have set up my app using Express, and so I would like to have a real GET request to the server here invoking the data from the newly created model. So I would like to load the page and not just change the view.
One way to do this (I think) would be to just have
window.location = 'messages/'+id;
as the last line above, but I seem to have the impression this is not good practice for Backbone in general.
Otherwise, could just create the message model inside of the render method, and then write its id directly into the href of the button when the view is rendered, but this also seems messy :
render : function() {
var message = new Message({model : model)};
var id = message.get('id');
$('a #button').attr('href', '/messages/'+id);
}
Any ideas on how I could set this up in a more elegant way? Thanks in advance!
Are you sure you want to actually change the browser page to a new window location? Doing that will cause all your javascript and everything else to have to reload. if you need to invoke a GET to the server to get the information for that model id, you just need to call fetch on a model with an id attribute.
From the little code you have here, this may be more along the lines of what you're trying to do:
MessageView = Backbone.View.extend({
events : {
'click #button' : 'go_here'
},
go_here : function(model) {
//myID is the id of your message you want to get from the server
//I'll leave it up to you on how you get the id of what you
//want from that button
//I'll also assume that you have a router setup somewhere
//to handle navigation
MyApp.MyRouter.navigate("messages/"+id, {trigger: true});
}
});
Then, in your router you'd have a route setup to watch for that:
routes: {
"messages/:id" : "showMessage"
}
And in your showMessage function:
showMessage: function(id) {
var message = new Message({id: id});
message.fetch({success: function(model) {
//render view of for the message to be shown
var messageView = new MessageView({model: model});
messageView.render();
});
}
When you create the view this way, it will be created with a model that already has all the data for your message in its attributes.

Resources