Custom button override in Salesforce - javascript

I want to create a custom button override in Salesforce. I'd like to override the delete button so that instead of deleting, I just want it to change the record type.
My custom object is Absence__c

Try this:
You only have to edit the Page Layout, remove the "delete" button,
Then create a custom button named "delete", set the javascript to button's behavior. Finally add that button to the page layout.
This is an example code for the custom button:
{!REQUIRESCRIPT("/soap/ajax/15.0/connection.js")}
var AbsenceUpdate = new sforce.SObject("Absence__c");
AbsenceUpdate.Id='{! Absence__c.Id }';
AbsenceUpdate.RecordTypeId = '{new record type id}';
if(AbsenceUpdate!=null)
{
try
{
updateOpp = sforce.connection.update([AbsenceUpdate]);
window.location.reload();
}
catch(e)
{
alert('error : ' + e);
}
}

I think your best bet is a controller extension and an override of the existing Delete button.
<apex:Page action="changeRTRedirect"
standardController="Absence__c" extensions="DeleteOverrideExtension">
</apex:page>
public class DeleteOverrideExtension {
private SObject record;
public DeleteOverrideExtension(ApexPages.StandardController controller) {
record = controller.getRecord();
}
public PageReference changeRTRedirect() {
record.RecordTypeId = '[YOUR NEW RT ID]';
update record;
//where do you want to send users now, maybe the Absence__c tab?
return Page.MyPageHere;
}
}

Related

Update a field on a Netsuite record using .set() not working

So I'm currently trying to update the title field on a NetSuite Quote record from an input on the front-end so a user can add the title themselves.
When submitting the quote I can set the title and see that it has updated the backbone model, however when the page loads the model has set the title back to null.
The functionality already exists with the memo area, and I have copied all the functions to replicated this for the title, however the memo continues to be updated, but the title does not.
I'm fairly new to the SuiteScripting and try to avoid it as much as I can, but I think the field isn't being updated and therefore not available in the model on other pages.
enter , update: function (record_type, id, data_model)
{
if (record_type && id)
{
this.recordId = id;
this.data = data_model;
this.record = this.getTransactionRecord(record_type, id);
//#property {Transaction.Model.Get.Result} currentRecord This property is used so when performing any update
//operation you can know what is the current state
//This property is only present when performing an update operation
this.currentRecord = this.get(record_type, id);
this.setPaymentMethod();
this.setLines();
this.setAddress('ship', this.data.shipaddress, 'billaddress');
this.setAddress('bill', this.data.billaddress, 'shipaddress');
this.setMemo();
// Set's our Quote title
this.setTitle();
// Set's our PO Number and SLC Number
this.setCustomFields();
}
}
/**
* Adds fields to the Sales Order when generated via Quotes (possibly via other methods as well)
*/
, setCustomFields: function ()
{
if (this.data.custbody_slc_number) {
this.record.setFieldValue('custbody_slc_number', this.data.custbody_slc_number);
}
if (this.data.otherrefnum) {
this.record.setFieldValue('otherrefnum', this.data.otherrefnum);
}
}
/**
* #method setTitle Sets the title attribute into the current transaction
* #return {Void}
*/
, setTitle: function ()
{
this.record.setFieldValue('title', null);
if (this.data.title)
{
this.record.setFieldValue('title', this.data.title);
}
}
//#method setMemo Sets the memo attribute into the current transaction
//This method does not use any parameters as it use this.data and this.record
//#return {Void}
, setMemo: function ()
{
this.record.setFieldValue('memo', null);
if (this.data.memo)
{
this.record.setFieldValue('memo', this.data.memo);
}
}
This is where the setTitle() function is created and called on update.
, submit: function () {
this.wizard.model.set('memo', this.$('[data-type="memo-input"]').val());
this.wizard.model.set('title', this.$('[data-type="title-input"]').val());
console.log(this.wizard.model);
return jQuery.Deferred().resolve();
}
And this is the submit function.
So on submit the model is being updated using the .set() function, however it is not saving this field to the record.
I've been banging my head against this for a while now and I can't see to figure out what different between the setMemo and the setTitle.
Any help would be amazing, I would love to understand how to add data to records from the front-end but it's quite a maze to work out whats going on.
Thanks!
UPDATE
I've traced the data path back from the view submit function, to the configuration, and then to the submit to the server.
I have can see that when logging the variable through these stages, the title field gets set and saved until the page reloads to the quote confirmation page where in the 'changed' section of the model the title is redefined to 'null'.
Here is the submit function that submits the model:
, save: function ()
{
_.first(this.moduleInstances).trigger('change_label_continue', _('Processing...').translate());
var self = this
, submit_opreation = this.wizard.model.submit();
submit_opreation.always(function ()
{
_.first(self.moduleInstances).trigger('change_label_continue', _('Submit Quote Request').translate());
});
return submit_opreation;
}
}
I believe that it's a suitescript issue and I don't have a lot of experience with suitescript
setTitle: function ()
{
// this.record.setFieldValue('title', null);
if (this.data.title)
{
this.record.setFieldValue('title', this.data.title);
}
}
This function sets the title to 'null' however when hard coding a value here or just removing the if statement the title is still set to 'null'.
As I'm new to SuiteScripting, could anyone also point out how I could log 'this.data'?
From what I can see the submit-function maps the input-values correctly to the (local) model ("I can [...] see that it has updated the backbone model"), but it does not finally save that model to the (remote) database after clicking on the submit button ("however when the page loads the model has set the title back to null."). This would usually be done by implementing the Backbone.Model.save - method.
You could therefore try to change your submit-function to the following:
submit: function () {
this.wizard.model.set('memo', this.$('[data-type="memo-input"]').val());
this.wizard.model.set('title', this.$('[data-type="title-input"]').val());
var dff = jQuery.Deferred();
// Send model state to database
this.wizard.model.save(null, {
success : function(data, response) {
console.log('success: model saved', data);
dff.resolve(data);
},
error : function() {
console.log('error: model not saved');
dff.reject();
}
}
return dff.promise();
}

How to track changes in form object in aurelia to activate revert button

We are using Aurelia to crate a single page application where we are creating/Editing Employee details. In Edit employee form, we need to give functionality to revert local changes if any. But the trick is to disable button if there are no local changes
I tried using computedFrom, but its only observing the properties and not the complex object.
Here is a sample code -
import {bindable, computedFrom} from 'aurelia-framework'
export class Employee {
#bindable employee
#computedFrom('employee')
enableRevert() {
return true;
}
revert() {
// revert functionality goes here
}
}
Thanks for your help!
employee.html
<button disabled.bind="!hasChanged()">Revert</button>
employee.js
attached() {
Object.assign(this.originalEmployee, employee);
}
hasChanged() {
// Like #Favio said, iterate over an original copy of the employee object.
for (let p in employee) {
if (employee[p] !== this.originalEmployee[p]) {
return true;
}
}
return false;
}

Button being called multiple times

I have a search page and an edit page. I search for a user and then when I get the results, I'm able to edit the user. I'm using CanJS and I've defined routes for each page.
, 'search route': function (data) {
new FormUserQuery('#formArea', {});
}
}
, 'edit/:id route': function (data) {
new FormUser('#formArea', {}).renderView(+data.id);
}
}
In FormUser I have a click event for the saveButton. If I search a user and then press the edit button, change something and save the changes, it works fine. But if, after saving, I go back to the search page and do the same things as I did before, the save button is being called twice.
I have no idea why this is happenning. What am I doing wrong?
Edit
I made it work. Whenever I clicked on a new edit button, somehow the view was being placed on top of another, it wasn't replacing the old one.
So I tried this and it worked:
, 'search route': function (data) {
if (typeof self.form === 'undefined')
{
self.form = new MegaControl.FormUserQuery('#formArea', {});
}
else {
self.form.destroy();
self.form = new MegaControl.FormUserQuery('#formArea', {});
}
}
, 'edit/:id route': function (data) {
if (typeof self.form === 'undefined') {
self.form = new MegaControl.FormUser('#formArea', {})
self.form.renderView(+data.id);
}
else {
self.form.destroy();
self.form = new MegaControl.FormUser('#formArea', {});
self.form.renderView(+data.id);
}
}
You shouldn't need to call destroy manually as you are doing. The issue is that you are using the same DOM element for both views (#formArea).
Can will call destroy automatically for you when an element is removed from the DOM, so that is the step that is missing.
So maybe instead of reusing the same element, you could append an element first and pass that newly created element to the control. Something like:
'search route': function (data) {
$('#formArea').empty(); // this will remove previous elements and trigger destroy automatically
var view = $('<div>');
$('#formArea').append(view);
new FormUserQuery(view, {});
}

asp.net IScriptControl $create order

I have two script controls (code is very simplified):
class Form : IScriptControl
{
Panel pnl;
Button trigger;
public Form()
{
pnl = new Panel();
trigger = new Button();
IPresenter p = new Popup();
p.SetContent(this.pnl);
this.Controls.Add(trigger);
}
}
class Popup : IScriptControl, IPresenter
{
public void SetContent(Control content)
{
this.Controls.Add(content);
}
}
Now in the HTML output, i see the following (again very simplified):
<div id="ctrlForm">
<div id="ctrlPopup">
<div id="ctrlFormPnl"></div>
</div>
<div id="ctrlFormTrigger"></div>
</div>
And script:
Sys.Application.add_init(function() {
$create(Form, {"_presenter":"FormPresenter"}, null, null, $get("ctrlForm"));
});
Sys.Application.add_init(function() {
$create(Popup, {"_isOpen":false}, null, null, $get("ctrlPopup"));
});
Question: How I can do, that the script that creates the popup appears on page before script of form...in other words, when initializer of the ctrlForm control executes, I want to get reference to forms presenter.
I hope I clearly explained what I want to do. Thanks.
In order to archive you goal you should let the child controls to register with ScriptManager before your control.
This can be done if you register your control with ScriptManager inside overridden Render method, after calling base.Render(...)
like that:
protected override void Render(HtmlTextWriter writer)
{
// Let child controls to register with ScriptManager
base.Render(writer);
// Now, when all the nested controls have been registered with ScriptManager
// We register our control.
// This way $create statement for this control will be rendered
// AFTER the child controls' $create
if (this.DesignMode == false)
{
ScriptManager sm = ScriptManager.GetCurrent(this.Page);
if (sm != null)
sm.RegisterScriptDescriptors(this);
}
}

Magento: Tab click event

Anyone knows a way to listen for clicks on magento tabs with javascript on the backend, say you want to do something everytime someone clicks a tab on the edit customer page. adminhtml/tabs.js has this:
tabMouseClick : function(event) {
var tab = Event.findElement(event, 'a');
// go directly to specified url or switch tab
if ((tab.href.indexOf('#') != tab.href.length-1)
&& !(Element.hasClassName(tab, 'ajax'))
) {
location.href = tab.href;
}
else {
this.showTabContent(tab);
}
Event.stop(event);
},
But no use, anyone has any idea? I also tried using standard prototype js observer:
Event.observe("product_info_tabs", "click", function ()
{ alert(1);
});
Did not do anything either. The solution should not modify the core, since this would add many problems with upgrades and maybe future magento versions.
To listen for clicks on Magento tabs (varienTabs) in the backend, you only need to add your custom observers to the existing ones. Using your example ("edit customer page" in backend) this would be:
var myTabs = $$("#customer_info_tabs li a.tab-item-link");
for (var i = 0; i < myTabs.length; i++) {
Event.observe(myTabs[i], "click", function (event) {
var tab = Event.findElement(event, "a");
// insert your custom code here
alert(tab.id);
Event.stop(event);
});
}
To implement custom observers without changing the core files (breaking upgradability), you could override the appropriate admin controller action.
For example, override Mage_Adminhtml_CustomerController::editAction():
<!-- app/code/local/My/Adminhtml/etc/config.xml -->
<config>
<modules>
<My_Adminhtml>
<version>0.1.0</version>
</My_Adminhtml>
</modules>
<admin>
<routers>
<adminhtml>
<args>
<modules>
<My_Adminhtml before="Mage_Adminhtml">My_Adminhtml</My_Adminhtml>
</modules>
</args>
</adminhtml>
</routers>
</admin>
</config>
Next, define your custom admin controller:
// app/code/local/My/Adminhtml/controllers/CustomerController.php
require 'Mage/Adminhtml/controllers/CustomerController.php';
class My_Adminhtml_CustomerController extends Mage_Adminhtml_CustomerController
{
public editAction()
{
// copy of Mage_Adminhtml_CustomerController::editAction() code here
}
}
Finally, in the overridden action, create an additional text block containing your custom observer script and append that block to the layout. For example at the end of editAction insert something like this:
:
$this->loadLayout();
$oBlock = $this->getLayout()->createBlock('core/text')->setText('
<script type="text/javascript">
var myTabs = $$("#customer_info_tabs li a.tab-item-link");
for (var i = 0; i < myTabs.length; i++) {
Event.observe(myTabs[i], "click", function (event) {
var tab = Event.findElement(event, "a");
alert(tab.id);
Event.stop(event);
});
}
</script>
');
$this->getLayout()->getBlock('left')->append($oBlock);
$this->renderLayout();
:
Old answer, but since I am here:
Magento internals fire an event when teh tab is shown.
You can simply hook into that event.
varienGlobalEvents.attachEventHandler('showTab', function(arg){
console.log(arg.tab);
});
Also not needed to inject via overriding controller.
Just add in yoru own custom layout directive, and load js accordingly.

Categories

Resources