I have written an event handler on change of stage in BPF in Opportunity Entity:
var checkForAccountApproved = function (executionContext) {
var formContext = executionContext.getFormContext();
formContext.data.process.addOnStageChange(function (stageContext) {
var stageName = stageContext.getEventArgs().getStage().getName().toString();
if (some conditions) {
formContext.data.process.movePrevious();
}
else {
currentActiveStage.setValue(stageName);
formContext.data.entity.save();
}
});
};
Basically, on clicking next, I need to check if some conditions are not satisfied, then only, the next stage should be active, else, the current stage should be active.
If the conditions are not satisfied, i.e. the stage change happens, I will store the value of the current active stage in a field. If I am explicitly calling save, the event handler is again triggered.
Why is it so?
Probably a late answer but ...
don't use formContext.data.process.movePrevious() to cancel your stage change, as this will try to move the stage back and re-execute your pre-stage change ( this will probably keep looping till you get back to the first stage).. Instead use the below which cancels the stage change and stays at the current stage
executionContext.getEventArgs().preventDefault();
Related
I have a scheduler with custom events. In the edit event popup, there is a cancel button. The scheduler is from a javascript library, so not of my creation, I only created its custom functionality.
So in the edit popup (which triggers edit event), I set a variable to hold the current state of the event data. Then if I make any changes and press cancel instead of save, the cancel event is triggered. In the cancel event, the 'currentState' event data is now changed to the new state of all the changed data, which I don't want. I need the old data so I can revert it all back, then refresh scheduler.
This is my cancel event:
cancel: function(e){
console.log('Cancelling', e);
var kendoEvent = new kendo.data.SchedulerEvent();
var schema = e.sender.dataSource.options.schema.model.fields;
console.log(e.sender.dataSource.hasChanges());
console.log(currentEventState);
$.each(schema, function(index, value){
//console.log(value);
console.log(index);
kendoEvent[index] = e.sender.oldEventData[index];
if(index == 'ownerId'){
kendoEvent.ownerId = currentEventState.ownerId[0].value;
}
});
console.log(kendoEvent);
console.log(getIndexById(kendoEvent.taskId));
eventData[getIndexById(kendoEvent.taskId)] = kendoEvent;
e.sender.dataSource.read();
if(e.event.id != '0'){
dontUpdate = 1;
//e.sender.dataSource.sync();
}
},
Where e.sender is the scheduler, and e.event is the event data (with any changes that were made). In the edit event the first thing I do is add oldEventData field to e.sender and set it to e.event. But... if changes are made to e.event AFTER e.sender.oldEventData is set, e.sender.oldEventData STILL gets changed to reflect all the changes made...
How might I preserve this old data so I can revert it back? I tried just doing a global variable instead of creating a new field in e.sender, but after setting the global variable to e.event, it still reflected any changes made >:(.
Discovered that cloning the data into the field e.sender.oldEventData prevented it from being tied to e.event. So e.event could change without messing with the old data.
This was achieved with a simple JSON.parse(JSON.stringify(e.event)).
I attempted Object.freeze(e.sender.oldEventData), which kept the old data, but made it completely unable to modify at all, so wasn't the best solution for me.
I have an app where you can enter some information about a customer. I have the problem that this information easily can be overwritten by other changes in the app.
I want:
A textarea showing the information
The message shown should update as changes are made to it in other places in the app
If the user has changed the message in the textarea, the message in the textarea should NOT be overwritten by server side changes or other changes in the app
When a save button is pressed, the model is updated
Simply doing this:
<textarea ng-model="customer.info"></textarea>
<button ng-click="save(customer)">Save</button>
won't work, because if something is changed to the customer object on the server, the information field will be reset and the user's changes will be overwritten.
Update:
In response to your comment/updated question: I'd simply track the state of the textarea using a couple of event listeners, that check if the user changed the value. If so: the textarea is no longer kept in sync with the server data.
I also check if the textarea has focus, if that is the case, the value should not be updated, because the user might be editing its contents.
Lastly, I've attached a blur event handler, that checks the value again, in case the user "undoes" changes. If a user adds a char by accident, and removes it later on, the textarea's value might be the same as the last known value that came from the server, in which case, the textarea's value should be kept in-sync again.
I've set up a simple fiddle that uses an interval to do all this. Replace the interval-related code with your worker, ajax callback or whatever it is you're using. If it's a worker, unsetting the interval should be replaced with unbinding the onmessage handlers with a handler function that syncs the textarea or doesn't sync the textarea. Alternatively use a single function that checks the changed flag whenever it wants to change the textarea's value. Plain and simple.
Here's the fiddle
And here's the code (the fiddle version contains some actual comments that explain various bits and pieces):
(function (txt)
{
var initialValue = txt.value,
changed = false,
id,
callback = function()
{
if (changed === false)
initialValue = (txt.value += ' Server-sync');
else
{
clearInterval(id);
id = null;
}
};
txt.addEventListener('change', function()
{
if (this.value !== initialValue)
changed = true;
}, false);
txt.addEventListener('focus', function()
{
changed = true;
}, false);
txt.addEventListener('blur', function()
{
if (this.value !== initialValue)
changed = true;
else
{
changed = false;
id = setInterval(callback, 5000);
}
}, false);
id = setInterval(callback,5000);
}(document.querySelector('#foo')));
Initial answer
Like I said in my comment:
<textarea ng-model="customer.info" id='foo' readonly></textarea>
prevents the value of the textare from being altered by the user, but you can still set/change its value in your JS code:
var changeTxt = (function(txt)
{
return function(addVal)
{
txt.value += addVal;
};
}(document.querySelector('#foo')));
Demo
To keep the value of the textArea in sync, you could perform an AJAX call prior to making any changes to the value client side, or create a worker "thread" that polls the server for changes that have been made since the value was last fetched.
Seeing as you're using angular.js, I must admit that I don't have any experience with how angular can be best used to solve your issue, but a quick google search lead me to 3-way data binding, which does look rather promising.
I have declared a class based on dgrid/OnDemandGrid. The class can display a selected record for editing using dojox/form/Manager, which I have placed in a dijit/Dialog. When editing the first record everything works fine, but subsequent submits seem to accumulate and fire the submit event repeatedly, although the put method only seems to get called once per submit.
Please see the Firebug output here http://speedyshare.com/hQBuP/submitRecord.png (just click the file name at the top)
The edit and submit methods look like the code below. Any suggestions to what is wrong with my code are welcome.
Thanks in advance.
editRecord: function() {
this.editMode = "edit";
var rec = this.store.get(currentRowId);
var form = registry.byId(this.editFormId);
var dialog = registry.byId(this.dialogId);
form.reset();
form.setFormValues(rec);
form.on("submit", lang.hitch(this, this.submitRecord));
var cancelButton = registry.byId(this.cancelButtonId);
dialog.show().then(function(){cancelButton.focus();});
},
submitRecord: function(event) {
// Testing counter
if(!this.counter)
this.counter = 1;
else
this.counter++;
console.log("Submit event: " + this.counter);
// Get form, dialog and retrieve record
var form = registry.byId(this.editFormId);
var dialog = registry.byId(this.dialogId);
// Check validity
if(!form.validate()) {
return false;
}
var rec = form.gatherFormValues();
// Put record in store
this.store.put(rec).then( /*..... pop up status or error toaster (code omitted)..*/ );
// Dismiss dialog
form.reset();
dialog.hide();
// Stop submit event
event.stopPropagation();
event.preventDefault();
return false;
}
You are attaching a submit event listener every time editRecord is called, which is presumably every time you show your dialog. You really only want to be attaching that listener once. Since you're never removing it and adding it every time, you're effectively causing the same function to fire n+1 times on the next submit after each time editRecord is called. Hook up the submit event handler exactly once after creating the form instead.
If I had to guess, the reason store.put is only being called once is because you reset the form afterwards, so subsequent repetitive calls to submitRecord will fail the validate call and bail out before the put call.
My Code is as below.
$(document).ready(function($)
{
var form = $("#video_detail_form");
var name = $("#videoTitle");
var nameInfo = $("#valid_videoTitle");
function validateName(){
//if it's NOT valid
var titleValue=$.trim(name.val());
if(titleValue.length == 0){
nameInfo.text("Please Enter Title");
return false;
}
//if it's valid
else{
nameInfo.text("");
return true;
}
}
name.blur(validateName);
name.keyup(validateName);
name.change(validateName);
$('#editVideoCancel').click(function(){
cancelVideoDetailAjaxCall( '/video/cancelVideoDetail', callBackCancelVideoDetail);
});
});
My cancelVideoDetailAjaxCall function changes text of the videoTitle input box. But my this code is not capturing that event by name.change.
If I change manually then it captures it. So when dynamically my callback function is changing the text then change event is not capturing it.
How should I capture that change?
You can actually extend your value change catching to all changes coming from some script using the jQuery val method, by setting a custom setter in jQuery.valHooks.
Imagine you change the input type to myCustomType, then you will implement jQuery.valHooks.myCustomType.set method which will be called each time val is used to set the input value, and you will include your specific call here. But I insist : it is not a best practice.
You will surely find explicit code on the web for that hooks.
As comments have mentioned, if you programmatically change the value via jQuery you must also trigger that change programmatically, if you want anything subscribed to it to register that change.
You can always make up your own events and trigger them accordingly if you don't want to "interfere" with other things already subscribed to regular events:
$el.on('mycustomevent', function() { ... })
$el.trigger('mycustomevent');
You can even subscribe with the same callback for the 'regular event' and your 'custom event':
$el.on('change', myChangeCallback);
...
$el.on('mycustomevent', myChangeCallback);
If you don't want to keep typing $el.val('...').trigger('mycustomevent') repeatedly, then declare a helper function that does that for you:
// helper function for changing the value
function changeInput(newVal) {
if(!this.$target) this.$target = $('#text'); // stash the target for reuse
this.$target
// programmatically change the value; does not fire 'change' event
.val(newVal)
// now trigger your custom action that behaves
.trigger('customaction'); // add extra parameters, etc
}
Full example: https://jsfiddle.net/drzaus/ds6g745s/8/
I have a contact form that sends a value to a hidden input on successful completion of the sendmail function. I want to detect this value change and then use it to apply a class to a div/paragraph.
I asked a similar question recently and I'm aware that this requires the script to continually check the doc after DOM is loaded but even after adding .change() it just doesn't seem to want to add the class.
Here's the jQuery:
$(document).ready(function() {
$("#acf_success_sent").change(function(){
if ($("#acf_success_sent").val() == "1"){
$("#acf_verified").addClass('gone');
}
});
});
any help would be great. here's a link to a test version of form in case you're interested, everything works except the verified symbol doesn't disappear after a successful send http://seeshell.me/forms/contact.php
There'll be no "change" event fired when code updates the value of your <input> element, so the handler you've registered won't run. What you could do however is fire "change" from a watchdog:
var watchdog = setInterval(function() {
if ($('#acf_success_sent').val() !== originalValue)
$('#acf_success_sent').trigger('change');
}, 100);
How you set up "originalValue" depends on your application. You could, for example, keep a separate ".data()" value, and watch for whenever your saved value differs from the current "value" attribute. Or you could keep the value in a closure variable:
var watchdog = (function() {
var $acfSuccessSent = $('#acf_success_sent'), cachedValue = $acfSuccessSent.val();
return function() {
if (cachedValue !== $acfSuccessSent.val())
$acfSuccessSent.trigger('change');
};
})();