How to trigger a server side Suitelet Script from Client Script in 2.0? - suitescript

I have a suitelet script (server side- working on back end) which needs to be triggered from a client script without getting navigated to that Suitelet page.
I tried using resolveScript and it makes the script work but it navigates the page to the suitelet page which is blank.
Can anyone suggest me which API to use which will trigger my Suitelet Script but remain on the same page where I m right now?
My Code:
function goToOpportunityRec() {
var rec = curr.get();
/* if i uncomment this setValue, the script stops working
curRec.setValue({
fieldId: 'custrecord_awt_status',
value: 3,
ignoreFieldChange: true
}); */
var suiteletURL = url.resolveScript({
scriptId: 'customscript_mx_awtitem_sl',
deploymentId: 'customdeploy_mx_awtitem_sl',
returnExternalUrl: false
});
suiteletURL += '&id=' + rec.id;
newWindow = window.open(suiteletURL);
}
If I remove the window.open, the Suitelet wouldn't trigger.
Please suggest a solution

In my case, I called my suiteletscript when I click button[Client script] on record.
function pageInit(context) {
}
function onButtonClick() {
document.location.href='/app/site/hosting/scriptlet.nl?script=726&deploy=1';}
exports.onButtonClick = onButtonClick;
exports.pageInit = pageInit;
return exports;});

Related

Sign in API end point wont get invoked unless you clear the browsers cache and then reload the page

I have made a website using asp.net and I have set up a sign-in feature that uses OpenID specifically Steam. I have a web API that gets called and that procs the challenge for the open id. When the user clicks sign in it opens a new tab and browser and direct them to sign in api point. On my local pc, it works perfectly however on a hosted app service on Azure it does not. When the window opens it does not call the API. The only way to call the API is to clear the cache (Shift + Ctrl + R). This then reloades the page and the API get called and it works perfect. If I dont clear the cache its just a blank page.
Here is the code for the API
[HttpPost("api/signin"), HttpGet("api/signin")]
public async Task<IActionResult> SignIn(string type)
{
string provider = type;
// Note: the "provider" parameter corresponds to the external
// authentication provider choosen by the user agent.
if (string.IsNullOrWhiteSpace(provider))
{
return BadRequest();
}
if (!await HttpContext.IsProviderSupportedAsync(provider))
{
return BadRequest();
}
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
return Challenge(new AuthenticationProperties { RedirectUri = "api/saveuser" }, provider);
}
Here is the code for the function that opens the new window and points to the API when a button is pressed.
handleLoginSteam = () => {
let winHeight = window.screen.height / 1.5;
let winWidth = window.screen.width / 3;
const win = window.open(
'/api/signin?type=Steam',
'Discord Sign In', "height=" + winHeight + ",width=" + winWidth + ",top=" + ((window.screen.height - winHeight) / 2) + ",left=" + ((window.screen.width - winWidth) / 2));
win.opener.location.reload();
const timer = setInterval(() => {
if (win.closed) {
clearInterval(timer);
this.fetchUserData();
}
}, 500);
}
This is a picture of the new window not calling the api
At this point pressing ctrl shift r is the only way to invoke the steam sign in.
I tried adding a random parameter to the link that gets passed to the window to stop caching but it doesnt work!
If any one can help me out I would be greatly apreciated im quite new to asp.netS.
Went through the code seems you are trying to achieve opens the new window and points to the Signin API when a button is pressed and RefreshParentWindow task. Now, based on your code let’s take a look at your code line-by-line.
This is the code to open a popup window.
const win = window.open(
'/api/signin?type=Steam',
'Discord Sign In', "height=" + winHeight + ",width=" + winWidth + ",top=" + ((window.screen.height - winHeight) / 2) + ",left=" + ((window.screen.width - winWidth) / 2));
On the same page(I assume) you have
win.opener.location.reload(); //this will refresh the parent window
const timer = setInterval(() => {
if (win.closed) {
clearInterval(timer);
this.fetchUserData();
}
}, 500);
}
setInterval() It repeats the statements in the specified intervals REPEATEDLY. Now, you are checking if the window is still opened or not using this line of code.
if (win.closed)
this check every second even if the window is closed!
Reference: https://www.w3schools.com/jsref/prop_win_closed.asp
Now follow these steps:
Open child window using the script on your parent page(you already have it there).
Get rid of the code that checks if the window is closed or not. You don't need it, in any way.
When you are done with adding a new record from you child window call these statements.
opener.location.reload(); //This will refresh parent window.
window.close(); //Close child window. You may also use self.close();
The above two lines will be written on the child page. Maybe on buttons click.
<input type="button" onclick="Signin()" value="Signin" />
function AddRecord(){
//Add newrecord.
opener.location.reload(); //This will refresh parent window.
window.close(); //Close child window. You may also use self.close();
}
Reference : https://www.codeproject.com/Questions/1097734/How-to-reload-refresh-the-parent-window-after-chil

Insert form shifts to the left after running the AMU.loadRecordByKey function

I am calling AMU.loadRecordByKey(widget) in the onAttach event of an edit form (not an insert form) to display the correct record that was previously submitted.
Here is the function from the App Maker University script library:
/**
* Loads a record by Key
* Checks URL first and then uses page parameter RECORD_ID
* Use in the page onAttach, recommend a deticated datasource
* #param {Object} widget Should be the page
*/
AMU.loadRecordByKey = function(widget){
google.script.url.getLocation(function(location) {
var recordId = location.parameter.record_id;
var properties = app.pages[app.currentPage.name].properties;
if (recordId !== undefined && recordId !== null) {
widget.datasource.query.filters._key._equals = recordId;
}else if(properties.RECORD_ID !== null){
widget.datasource.query.filters._key._equals = properties.RECORD_ID;
}else{
// alert('No Record ID Found');
}
widget.datasource.load();
});
};
When the form initially opens its displays fine, but right after the AMU function is called, everything on the form shifts to the left. There is no error in the function (I tested this by putting alerts between every line).
Any ideas?
The script just loads datasource. Once items are loaded rendering engine does its work. So, there is nothing to do with the script, you need to look at your layout.
Keep in mind, that ideally you need to use this script with datasource in manual load mode, to avoid double data loading and blinking.
Side note:
// this
var properties = app.pages[app.currentPage.name].properties;
// can be simplified to this
var properties = app.currentPage.properties;

How to check whether the web resource control is loaded or not in Dynamics CRM 2016

Have to access the Webresource control from another webresoucre control
Used the following javascript ,
var webResource = $(window.parent.Xrm.Page.getControl(webResourceName).getObject().contentWindow.window.document.getElementById(dropDownName));
But some times it is working correctly ,some times it returns null value.
So it is possible to check whether the webresource is loaded or not.
You have a number of options.
Have your web resource trigger code
My favorite approach is to go the other direction: In your web resource, add code to start execution on the parent CRM form. You can use jQuery's ready method or one of the many approaches that you can read about here on SO that doesn't involve jQuery. If you're using jQuery, your web resource could have something like this:
$.ready(function() {
window.parent.Xrm.Page.getAttribute('name').setValue('test'); // or whatever your webresource needs to do
});
The idea is that the web resource triggers some logic when it's ready so that you can avoid the trouble of having to detect when the web resource is finished loading.
Use jQuery's load method
I can't remember if I've actually tried this, but you should be able to use jQuery's load method. In the script on the CRM form, do something like this:
$('iframe#WebResource_xyz').on('load', function() {
// Here, the 'this' object will refer to the iframe object
this.contentWindow.document.getElementById(dropDownName); // you might have to tweak this slightly, didn't test it
});
Detect when the web resource is ready
This approach does what you're asking for and is what I used to use before jQuery was available on forms out of the box (including it for future readers who might be on an older version of CRM where jQuery was not available). It waits for the webresource to finish loading and then invokes a callback. Add this function to the script that loads on your CRM form:
// Waits for web resource to be ready and then invokes the callback.
// webResourceId: the id of either a web resource or an iframe on the form
// urlCheck: this string will be checked for in the iframe's url to make
// sure it is on the right page. can be any part of the url,
// doesn't have to be the whole thing.
// callback: Called once the iframe is ready. The context of the callback
// method will be set to the iframe's window, so the callback can
// use "this" to refer to the iframe window.
function waitForWebResourceReady(webResourceId, urlCheck, callback) {
var tryCount = arguments[3] || 0;
var control = Xrm.Page.getControl(webResourceId);
if (!control ||
!control.getObject() ||
!control.getObject().contentWindow ||
!control.getObject().contentWindow.location ||
!control.getObject().contentWindow.location.href ||
control.getObject().contentWindow.location.href.indexOf(urlCheck) < 0 ||
control.getObject().readyState !== 'complete') {
if (tryCount > 50) {
console.log("waitForWebResourceReady: " +
"Failed to reach ready state on " + webResourceId);
return;
}
console.log("waitForWebResourceReady: " + webResourceId + " not ready yet");
window.setTimeout(function () {
waitForWebResourceReady(webResourceId, urlCheck, callback, ++tryCount);
}, 20);
return;
}
console.log("waitForWebResourceReady: " + webResourceId + " is ready");
callback.call(control.getObject().contentWindow);
}
and then use it like this:
waitForWebResourceReady('WebResource_xyz', 'mycontrol.html', function () {
// In this context, 'this' will refer to the window object of the webresource
var dropdown = this.document.getElementById(dropDownName);
// ....
});

ASP.Net Drop Down List not passing a value when updated using ajax

I have some jQuery that I'm using to open a pop-up window where a new consignor can be added to the database. The original window has a dropdownlist of all of the current consignors. When you add the new consignor in the pop-up window, that window closes and the original window then reloads the dropdownlist's data and selects the one just created.
All of that works perfectly. My issue is that when you fill out the rest of the form and submit it, it passes an empty string instead of the value of the selected item. Is this because it's an ASP.Net script? I don't know a lot about ASP.Net, but I've never had this issue with PHP. Can someone explain how I would go about refreshing the dropdownlist without refreshing the entire page and still get the list to pass it's value upon form submission?
My javascript code on the page that opens the pop-up and reloads the list is below:
function openConsignorAdd() {
var url;
url = "/admin/consignor/csAdd.aspx";
window.open(url, "WizardWindow", "width=400,height=500,resizable=yes,scrollbars=yes");
}
function loadNewAdded(fn, cs_txt_id) {
// var pagePath = window.location.pathname;
var pagePath = "/admin/getNewList.asp";
var paramList = "data=";
//Call the page method
$.ajax({
type: "POST",
url: pagePath + "?type=" + fn + "&cs_txt_id=" + cs_txt_id,
data: paramList,
success: function (data) {
//create jquery object from the response html
var $response = $(data);
//query the jq object for the values
var results = $response.filter('select#results').html();
if (fn == "consignor") {
$("select#<%=itemConsigner.ClientID%>").html(results);
} else if (fn == "cdr") {
$("select#<%=itemCDR.ClientID%>").html(results);
}
},
error: function () {
alert("Failed To Refresh!\n\nYou must manually refresh the page.");
}
});
}
My javascript code on the pop-up page to refresh the list is:
function refreshOpener(cs_txt_id) {
window.opener.loadNewAdded("consignor", cs_txt_id);
}
Those both work. And to get the value of my dropdownlist, I simply use:
if (itemConsigner.SelectedValue.ToString() != string.Empty)
{
itemCsTxtId = itemConsigner.SelectedValue.ToString();
}
with my dropdownlist being:
<asp:DropDownList ID="itemConsigner" runat="server" TabIndex="1"></asp:DropDownList>
If you need more info, just let me know. Any help is appreciated.
It seems that the issue is that since I am making the change after the page loads, the server does not see my new addition as one of the original options so ignores it completely. This is good so that people cannot just edit your forms I guess. So what I did was instead of getting the value of itemConsigner.SelectedValue, I grab the value for Request.Form["itemConsigner"] with the long ID. That way it doesn't validate that my submitted option was an original option.
Might be a silly observation but without all the code I'm not sure if this is the case. Are you just updating the original list with the id in the select options. The value needs to be populated as well for each. That could be why you are getting an empty value on after form submission.

How to open new window with streamed document in ASP.NET Web Forms

I have an ASP.NET Web Forms application. I want to have a button to post back to the server that will use my fields on my form (after validation) as parameters to a server process that will generate a document and stream it back to the browser. I want the form to be updated with some status results.
What is the best way to achieve this? Right now, I've got the button click generating the document and streaming it back to the browser (it's a Word document and the dialog pops up, and the Word document can be opened successfully) but the page doesn't get updated.
I have jQuery in my solution, so using js isn't an issue if that is required.
I have a very similar process on one of my servers, and the way I've handled it is to create a temporary document on the server rather than doing a live stream. It requires a bit of housekeeping code to tidy it up, but it does mean that you can return the results of the generation and then do a client-side redirect to the generated document if successful. In my case, I'm using jQuery and AJAX to do the document generation and page update, but the same principle should also apply to a pure WebForms approach.
This was way more difficult to do than I thought. The main issue is with opening a new browser window for a Word document. The window briefly flashes up, then closes - no Word document appears. It seems to be a security issue.
If i click a button on my page, I can stream the Word doc back as the response, and the browser dialog pops up allowing me to Open/Save/Cancel, but of course, my page doesn't refresh.
My final solution to this was to use a client script on the button click to temporarily set the form's target to _blank. This forces the response to the click on the postback to go to a new browser window (which automatically closes after the download dialog is dismissed):
<asp:Button Text="Generate Doc" runat="server" ID="btnGenerateDoc"
onclick="btnGenerateDoc_Click" OnClientClick="SetupPageRefresh()" />
My SetupPageRefresh function is as follows:
function SetupPageRefresh() {
// Force the button to open a new browser window.
form1.target = '_blank';
// Immediately reset the form's target back to this page, and setup a poll
// to the server to wait until the document has been generated.
setTimeout("OnTimeout();", 1);
}
Then my OnTimeout function resets the target for the form, then starts polling a web service to wait until the server process is complete. (I have a counter in my Session that I update once the process has completed.)
function OnTimeout() {
// Reset the form's target back to this page (from _blank).
form1.target = '_self';
// Poll for a change.
Poll();
}
And the Poll function simply uses jQuery's ajax function to poll my web service:
function Poll() {
var currentCount = $("#hidCount").val();
$.ajax({
url: "/WebService1.asmx/CheckCount",
data: JSON.stringify({ currentCount: currentCount }),
success: function (data) {
var changed = data.d;
if (changed) {
// Change recorded, so refresh the page.
window.location = window.location;
}
else {
// No change - check again in 1 second.
setTimeout("Poll();", 1000);
}
}
});
}
So this does a 1 second poll to my web service waiting for the Session's counter to change from the value in the hidden field on the page. This means it doesn't matter how long the server process takes to generate the Word document (and update the database, etc.) the page won't refresh until it's done.
When the web service call comes back with true, the page is refreshed with the window.location = window.location statement.
For completeness, my Web Service looks like this:
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class WebService1 : WebService
{
[WebMethod(EnableSession=true)]
public bool CheckCount(int currentCount)
{
if (Session["Count"] == null)
Session["Count"] = 0;
var count = (int)Session["Count"];
var changed = count != currentCount;
return changed;
}
}
Hopefully that helps somebody else!

Resources