netsuite add button to a record - button

I'm really new to NetSuite programming, and I'm having troubles adding a button to a record.
I want to add the button "Create Lead" next to the "Edit" and "Back" buttons of a record.
I have created a user event script, and this is my before load function:
function beforeLoad_addButton(type, form, request){
form.setScript(customscript_cue_new_lead_record);
form.addButton('custpage_add_createlead_button', 'Create Lead', 'createLeadRecord()');
}
I am setting a script to call a function on an other .js file.
This doesn't add a button like I would want it to. Can anyone help me figure this out? Thanks.

The first thing I see is that your call to .setScript needs to pass the ID as a string; you have no quotes. It should be:
form.setScript('customscript_cue_new_lead_record');
Not sure if this was just a typo, but if that's how your code is, then this is probably throwing an error with something like "customscript_cue_new_lead_record is not defined" if you check the execution logs of your User Event script, which is stopping the rest of the script from running so your button isn't being added.
Everything else looks correct to me. You've got the custpage_ prefix on your button ID, and the code to execute as a String.

I don't see anything wrong with your script so make sure that you already deployed the said script as user-event script.
Setup > Customization > Scripts > New
Select Type: "User-Event"
In the new window fill up the necessary details and upload the js file. Make sure to put this function.
Before Load Function : beforeLoad_addButton
This will add the button in view and edit mode. Hope that helps.

Related

Print Friendly Page

So I would like to be able to have a print button for entries in our database so users can print an entry via a print friendly "form".
My thought was to create a separate page, add labels and have those labels pull the relevant information.
I know I can add the open widget information via this code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.TestPrint);
But I'm running into a few problems:
I can't get the page to open in a new window. Is this possible?
window.open(app.pages.TestPrint);
Just gives me a blank page. Does the browser lose the widget source once the new window opens?
I can't get the print option (either onClick or onDataLoad) to print JUST the image (or widget). I run
window.print();
And it includes headers + scroll bars. Do I need to be running a client side script instead?
Any help would be appreciated. Thank you!
To get exactly what you'd want you'd have to do a lot of work.
Here is my suggested, simpler answer:
Don't open up a new tab. If you use showPage like you mention, and provide a "back" button on the page to go back to where you were, you'll get pretty much everything you need. If you don't want the back to show up when you print, then you can setVisibility(false) on the button before you print, then print, then setVisibility(true).
I'll give a quick summary of how you could do this with a new tab, but it's pretty involved so I can't go into details without trying it myself. The basic idea, is you want to open the page with a full URL, just like a user was navigating to it.
You can use #TestPrint to indicate which page you want to load. You also need the URL of your application, which as far as I can remember is only available in a server-side script using the Apps Script method: ScriptApp.getService().getUrl(). On top of this, you'll probably need to pass in the key so that your page knows what data to load.
So given this, you need to assemble a url by calling a server script, then appending the key property to it. In the end you want a url something like:
https://www.script.google.com/yourappaddress#TestPage?key=keyOfYourModel.
Then on TestPage you need to read the key, and load data for that key. (You can read the key using google.script.url).
Alternatively, I think there are some tricks you can play by opening a blank window and then writing directly to its DOM, but I've never tried that, and since Apps Script runs inside an iframe I'm not sure if it's possible. If I get a chance I'll play with it and update this answer, but for your own reference you could look here: create html page and print to new tab in javascript
I'm imagining something like that, except that your page an write it's html content. Something like:
var winPrint = window.open('', '_blank', 'left=0,top=0,width=800,height=600,toolbar=0,scrollbars=0,status=0');
winPrint.document.write(app.pages.TestPage.getElement().innerHTML);
winPrint.document.close();
winPrint.focus();
winPrint.print();
winPrint.close();
Hope one of those three options helps :)
So here is what I ended up doing. It isn't elegant, but it works.
I added a Print Button to a Page Fragment that pops up when a user edits a database entry.
Database Edit Button code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.FragmentName);
That Print Button goes to a different (full) Page and closes the Fragment.
Print Button Code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.ModelName_Print);
app.closeDialog();
I made sure to make the new Print Page was small enough so that Chrome fits it properly into a 8.5 x 11" page (728x975).
I then created a Panel that fills the page and populated the page with Labels
#datasource.item.FieldName
I then put the following into the onDataLoad for the Panel
window.print();
So now when the user presses the Print Button in the Fragment they are taken to this new page and after the data loads they automatically get a print dialog.
The only downside is that after printing the user has to use a back button I added to return to the database page.
1.
As far as I know, you cannot combine window.open with app.pages.*, because
window.open would require url parameter at least, while app.pages.* is essentially an internal routing mechanism provided by App Maker, and it returns page object back, suitable for for switching between pages, or opening dialogs.
2.
You would probably need to style your page first, so like it includes things you would like to have printed out. To do so please use #media print
ex: We have a button on the page and would like to hide it from print page
#media print {
.app-NewPage-Button1 {
display : none;
}
}
Hope it helps.
1. Here is how it is done, in a pop up window, without messing up the current page (client script):
function print(widget, title){
var content=widget.getElement().innerHTML;
var win = window.open('', 'printWindow', 'height=600,width=800');
win.document.write('<head><title>'+title+'/title></head>');
win.document.write('<body>'+content+'</body>');
win.document.close();
win.focus();
win.print();
win.close();
}
and the onclick handler for the button is:
print(widget.root.descendants.PageFragment1, 'test');
In this example, PageFragment1 is a page fragment on the current page, hidden by adding a style with namehidden with definition .hidden{display:none;} (this is different than visible which in App Maker seems to remove the item from the DOM). Works perfectly...
2. You cannot open pages from the app in another tab. In principle something like this would do it:
var w=window.parent.parent;
w.open(w.location.protocol+'//'+w.location.host+w.location.pathname+'#PrintPage', '_blank');
But since the app is running in frame nested two deep from the launching page, and with a different origin, you will not be able to access the url that you need (the above code results in a cross origin frame access error). So you would have to hard code the URL, which changes at deployment, so it gets ugly very fast. Not that you want to anyway, the load time of an app should discourage you from wanting to do that anyway.

CRM Ribbon Workbench - Hide + Button on Sub-Grid

I have a sub grid on a new entity called Issues, the sub grid is for another new entity called Cost Detail.
I have them both loaded into my solution called Issue, and have opened issue in the ribbon workbench.
What I want to do is when you are on the Issue form and can see the sub-grid I want to be able to hide the + button which is displayed. However when I have hidden this button in the ribbon workbench it also hides the add new button in the 'Associated View' therefore no records can be added.
How do I do it so that only the + button on the sub grid is hidden and not the other view?
EDIT:
In order to hide the add button, you either need to take away create privileges to the role that the user is in or you could do a hack(unsupported) like this:
function hideAddButton(){
var addButton = $('#NameOfGrid_addImageButton');
if(addButton.size())
addButton.hide();
else
setTimeout(hideAddButton, 1000);//checks every second to see if the button exists yet
}
and call the hideAddButton function on form load
There is one answer that I found. If you have a field that unique for that entity, then you can do it with a simple javascript code.
Here is steps that you must follow in ribbon workbench:
Right click the button and customise button.
Add an enable rule, in Steps section add an Custom Javascript Rule, that contains your library and function name, please make sure that default is true.
This must be in your javascirpt library :
function hideAddNew(){
if(Xrm.Page.getAttribute("yourField")){
return false;
}
else {
return true;
}
}
Add a command that contains the enable rule we created.
Add the command to button.
That's it. I test it, it is working.

Delete button with dialogOK in Grid

Im trying to implement delete button in GRID, same as with CRUD. I found dialogOK (http://agiletoolkit.org/blog/introduction-to-dialog-integration/), but guess i don't know how to use it right.
My code:
$gridC=$this->add('Grid');
$gridC->setModel('Campaign');
$gridC->addcolumn('Button', 'Delete')->js('click', $this->js()->univ()->dialogOK('Yey','Some custom javascript action here',$this->delete()));
//test only
$gridC->addcolumn('Button', 'Deletex')->js('click')->univ()->dialogOK('Are you sure?','This will take you to other page',$this->js()->univ()->page($this->api->getDestinationURL('admin')));
...
function delete(){
...
}
When i click on the button the delete() function starts right away, before i click ok. Also modal window is started :(
Any suggestions, i searched but couldn't find any good example..
NEXT DAY:
I checked the thing again, im almost shure i did it the right way, but i think i found a bug i dialogOK (http://agiletoolkit.org/blog/introduction-to-dialog-integration/)
I i re-create this example on any normal page:
$button = $this->add('Button');
$button->js('click')->univ()->dialogOK('Are you sure?','This will take you to other page',
$button->js()->univ()->page($this->api->getDestinationURL('index'))
);
The page redirects to index page, it doen't wait for OK button clicked. Insted it opens the dialogOK, but in the background redirects to index page..
I'm using atk 4.2.5 from master branch..
OK, that webpage has some bugs :( I would really appreciate if you could edit it and send in pull request in Github atk4-web.
Some tips to get you on road:
Try to use dialogConfirm() method not dialogOK(). Is it working then?
Try to add ->_enclose() after ->page(). That'll enclose JS expression in function.
If dialogConfirm() works and similar dialogOK() does not work, then I guess there is small bug in dialogOK() method. There should be close: if(fn)fn(), instead of close: fn, in atk4_univ.js file dialogOK method.
Can you try these tips and tell me what works for you? Sorry I didn't do that myself - I'm really out of time now :(

How to implement a button with a backend action in OpenWRT LUCI without UCI side effects

I am trying to to implement a button in LuCI which, when clicked , runs a shell script in the backend. This is the model code for this:
field_var_36 = section_var_7:option(Button,"buttonkk36",translate("ButtonKK"))
field_var_36.inputstyle = "apply"
field_var_36.rmempty = true
function field_var_36.write(self, section)
luci.sys.call('echo "ABCDEFG123" >/dev/null')
end
Though this is working it has some unwanted side-effects. All the unsaved modifications in the page are getting saved and I get a "n unsaved changes" notifications at the top. My guess is the the button if of type "submit" and all the fields inside the html "form" are getting "sumbitted". I dont want this to happen. The button needs to be standalone. Can this be done?
One other option I tried was using a template with button implemented in html. But I dont know how to connect this to the backend script. Is there a javascript API function in LuCI which takes the script as argument?
Thanks in advance for any help.
I did that using a view template.
You must set up an "entry(...)" in an "index()" function in the "controller/" directory.
The entry associates a path (last part of the LuCI URL's) with either a template view, cbi or LUA function, which is just what you want.
Pay attention that when you change by hand a controller file on the target openwrt device, you must delete /tmp/luci-indexcache so that the LuCI dispatcher does not use the older version.
Then in the template you can use "luci.dispatcher.build_url()" to create the URL that will make the controller call the function, and you put this as the target URL for your button (through either or or onClick="document.location=..."> and so on)

JavaScript puzzle to solve : window.confirm = divConfirm(strMessage)

Scenario is : old site which has lots of JS code already written. If user want to change all the alert messages to new age jazzy Div based alert which are very common using JQuery, YUI, Prototype... etc.
There are mainly tree JS dialogs
1. alert
To changes this its simple we just have to write new function which will show the div popup and show the message, after that override the window.alert
function showDivAlert(strMessage){
//div popup logic and code
}
window.alert = showDivAlert;
2. prompt
This too look easy to write function to accept the string and show the text box for input value. Now as return action is based on the click of "OK" button life is easy here.
function shoDivPromp(strMessage){
//div pop up to show the text box and accept input from the user
}
window.prompt = shoDivPromp;
3. confirm
Now above two were easy to override and modify the default dialogs but there is complication with the confirm.
However default JS confirm dialog stops JS execution and when user click OK or Cancel execution is resumed by determining the return value (true/false). But if we user div popup the execution is not stopped which is problem. We can still implement the confirm but in that case we have to bind methods for OK and CANCEL case which will be attached to OK and CANCEL button. With this function signature will be like.
function newConfirm(msg, fun OkAction(), fun CancelAction)
Now this is problem that this cant help me change the confirm dialog across the site as we did with alert();
Question
I am not sure whether its possible or not to achieve but i think can be using some JS pattern. So let me know if its possible.
Now this is problem that this cant help me change the confirm dialog across the site as we did with alert();
That's correct. It's not possible to reproduce the synchronous nature of the alert/confirm/prompt functions in native JavaScript. There is the non-standard method showModalDialog which can do it using a separate pop-up document, but it's not supported by all browsers and it's generally considered highly undesirable.
So the plug-in-replacement strategy isn't going to work. You are going to have to change every place you called these methods in the rest of the script.
The usual pattern is to do it using inline anonymous functions, to preserve the local variables using a closure, eg. replace:
function buttonclick() {
var id= this.id;
if (confirm('Are you sure you want to frob '+id+'?'))
frob(id);
wipe(id);
}
with:
function buttonclick() {
var id= this.id;
myConfirm('Are you sure you want to frob '+id+'?', function(confirmed) {
if (confirmed)
frob(id);
wipe(id);
});
}
If you need this to be preserved you would need to look at a further nested closure or function.bind to do it. If you have your call to confirm in a loop things get considerably more difficult.
Obviously you also have to ensure that critical global state doesn't change whilst the confirm box is up. Usually this risk is minimised by greying out the rest of the page with an overlay to stop clicks getting through. However if you have timeouts they can still fire.
All 3 methods actually stop js execution, not just the confirm, because they're all modal dialogs. Personally, I would try to keep everything as asynchronous as possible as modal dialogs prevent interaction with the current document.
Your best bet is to use callback functions from the new confirm popup as you suggested yourself.
I'm having a hard time understanding exactly what you want to achieve. It sounds like you want to do something like the following:
Run some javascript code
Display a "confirm" box
Wait until the ok button or cancel button is clicked
Continue code when user clicks ok, return when user clicks cancel.
The reason you want to do this is that overriding the function with something that makes use of callbacks would require rewriting each section of code that uses the confirm function. If you want my advice, I would go ahead and rewrite the code so that it performs asynchronously. There's no way you can delay script execution without locking up the document which includes the OK and Cancel actions of your dialog.
if you changed the roles Alert / Prompt / Confirm. slows the execution pending user interaction to run the following code.
Overriding these functions, the code continues its execution.
To achieve this you have to modify each part of the code and work as if you were with asynchronous functions.
Then you can use any plugin for windows as sexy-alert-box, and overwrite Alert / Prompt / Confirm
The function signature would simply be:
function newConfirm(msg, okAction, cancelAction);
and would be used as:
function newConfirm(msg, okAction, cancelAction){
var ok = doWhateverPromptIsNecessary();
if (ok) {
okAction();
} else {
cancelAction();
}
}
That is, to pass function "pointers" in to a function as arguments, simply pass in the function name without the (). The function signature is the same.

Resources