How to get the previous value of a field (javascript)

I want to present a dialogue after a user edits a field, and if they cancel the dialogue, I want to roll back the field to the previous value. However, I can’t figure out where I can get the previous value of the field. Requesting the document from the server is not an option, not only because it could have unintended side effects, but also because it might not be the value I want (e.g. if the value was changed without saving, and now the user is attempting to change it a second time).

I did discover this in the frm object:

frm.fields_dict[field].last_value

however, “last_value” is always the current value - i.e. the value that the user updated the field to.

For example, the form script

period_type: (frm) => {
    console.log('val', frm.doc.period_type);
    console.log('last val', frm.fields_dict.period_type.last_value);
    console.log('dict val', frm.fields_dict.period_type.value);
}

upon changing the value from “Cycle” to “Month” gives me the following output:

image

Where can I get the value for the field before the update.

2 Likes

I am not aware of a frappe-specific way to do this. With regular javascript, you could just put an event listener on the input or select, then store the current value when it gets focus.

1 Like

I created an Issue on GitHub regarding this problem. See JS Field Update pass previous Value · Issue #17183 · frappe/frappe · GitHub

My Workaround is as follows:
i set frm.<my_field>_prev_value = frm.fields_dict.<my_field>.value; in

  • the beginning of the refresh handler.
  • the end of a Handler attached to that field
frappe.ui.form.on("My Doctype", "my_field", function(frm) {
// Add functionality that uses frm.my_field_prev_value here
frm.my_field_prev_value = frm.fields_dict.my_field.value;
}

This way, you can add your logic at the marked position. Lets hope a fix for this gets implemented. I guess that the last_value thing is a Bug and that the field change handler is called too late, after the last_value is already updated. Lets See

CAVEAT:
In my case, i needed to set another field when my_field is cleared (set to null/empty string). This other field had a handler attached, that used frm.my_field_prev_value. Apparently, frm.set_value is not called synchronously. I had to implement it like this, otherwise frm.my_field_prev_value was already updated when the handler got called

frappe.ui.form.on("My Doctype", "my_field", function(frm) {
	if(!frm.doc.my_field){
		frm.set_value('my_other_field', null)
		.then(r => {
			frm.my_field_prev_value = frm.fields_dict.my_field.value;
		})
	}
	else{
		frm.my_field_prev_value = frm.fields_dict.my_field.value;
	}
});
1 Like

I ended up doing something similar, I think in the refresh method. It really should be built-in though. I voted up your issue :+1: