Why setting 'read-only' for a control in client scripts is actually toggling 'display' attribute?

Hi guys,

As the title says, I’m trying to do something really simple which is when ‘Make’ has no value selected then ‘Model’ should be disabled as the car models should be loaded based on the car make selected. I followed the docs to set the ‘read-only’ property but it actually shows/hides the ‘Model’ but does not change read-only or disabled.

Below is the script I created for the doctype. I’ve tried using frm.toggle_enable and frm.set_df_property, but none of them changes the read-only property.

frappe.ui.form.on('RockERP_Vehicle', {
	make(frm) {
	    var make=frm.doc.make;
		var enabled = make!=null && make!='';
		//frm.toggle_enable('model', enabled);
		//frm.set_df_property('model',  'disabled',  enabled? 0 : 1);
		frm.set_df_property('model',  'read_only',  enabled? 0 : 1);
	},
	refresh(frm){
	    var make = frm.doc.make;
	    var enabled = make!=null && make!='';
		//frm.toggle_enable('model', enabled);
		//frm.set_df_property('model',  'disabled',  enabled? 0 : 1);
		frm.set_df_property('model',  'read_only',  enabled? 0 : 1);
	}
})

@Rock_Lee You don’t need to write scripts . there is an option called “depends on” for the field model . just write (eval:doc.make!= null && doc.make!=“”; ) .
this will hide the field unless make is selected.

I actually need to disable it not hide it, thanks.

@Rock_Lee ok then use “Read Only Depends On” . it will disable the field when make is null.

BTW, the first thing I tried was just like what you suggested but it also hides the select box not changes the read-only property.

Below is the setting on ‘Model’ field.

@Rock_Lee ok , there is a strange behavior about read only. when the it’s read only and it has no data it just disappear . so consider setting a default value for model .

Actually I think this is a design but. The misconception is that a field that has no value and read only is not displayed at all.
While in reality, also the information that NO value is set in a read only field may be very important.
I guess a github issue should be raised.

@Rock_Lee What’s the type of field ‘model’ ? If it’s a data field. Then when you put read_only attribute over there it will be in hidden if it has no value in it. If there is any default value in model then it will be shown there in read_only state.

Thanks for your help. The behaviour is strange indeed.

Agree, it’s confusing as it behaves differently from the description. And in my case, having a default value might not be applicable as the car models need to loaded based on the car make selected.

The type is Link, I can’t give it a default value as the reason I mentioned above.

The Model is actually another doctype which means if I really need a default value I have to create an actual entry to cater for that, for example: Please select a make first like below.

And still need a client script to dynamically toggle Model, I.e., Clear the default value when a make is selected and set it as default value when make is cleared.

Literally that’s too much effort for such a simple feature, and I also need to reload the Model list when Make is changed. E.g, when BMW is selected then populate Model with all the models of BMW. @bahaou

I managed to use the client script below to achieve what I need, not ideal but solved the problem.

var model_placeHolder = 'Please select a make first';

function toggleReadOnly(frm, ele, readonly){
    if(readonly){
        frm.get_field(ele).input.setAttribute('readonly', readonly);
    }
    else{
        frm.get_field(ele).input.removeAttribute('readonly');
    }
}

function toggleModel(frm){
    var make=frm.doc.make;
	var makeSelected = make!=null && make!='';
	toggleReadOnly(frm, 'model', !makeSelected);
	var value = makeSelected?'': model_placeHolder;
	frm.set_value('model', value);
}

frappe.ui.form.on('RockERP_Vehicle', {
	make(frm) {
	    toggleModel(frm);
	},
	refresh(frm) {
	   toggleModel(frm);
	}
})

@Rock_Lee great job indeed . but you can just select a real model for that make instead of the new doctype

1 Like

I think this is a design flaw on frappe’s end. Null value is still information, and can be set through server side especially if the value is being set after database calls, which JS ‘read-only Depends On’ property cannot handle. A work around is that you have to have another placeholder field, just to guide the read-only state of that main field.