If you need to add custom interactions (if field is X then do Y), we have just the thing for you. You can easily add custom interactions, using our CrudField JavaScript Library. It's already loaded on our Create / Update pages, in the global crud
object, and it makes it dead-simple to select a field - crud.field('title')
- using a syntax that's very familiar to our PHP syntax, then do the most common things on it.
Here's everything our CrudField JavaScript Library provides:
crud.field('title')
-> returns the CrudField
object for a field with the name title
;crud.field('testimonials').subfield('text')
-> returns the CrudField
for the text
subfield within the testimonials
repeatable field;CrudField
:
.name
- returns the field name (eg. title
);.type
- returns the field type (eg. text
);.input
- returns the DOM element that actually holds the value (the input/textarea/select);.value
- returns the value of that field (as a string
);CrudField
:
.onChange(function(field) { do_someting(); })
- calls that function every time the field changes (which for most fields is upon each keytype);CrudField
:
.hide()
- hides that field;.show()
- shows that field, if it was previously hidden;.disable()
- makes that field's input disabled
;.enable()
- removes disabled
from that field's input;.require()
- adds an asterisk next to that field's label;.unrequire()
- removes any asterisk next to that field's label;.change()
- trigger the change event (useful for a default state on pageload);CrudField
:
.check()
- if the field is a checkbox, checks it;.uncheck()
- if the field is a checkbox, unchecks it;crud.action
-> returns the current action ("create" or "edit")The beauty of this solution is that... it's flexible. Since it's only a JS library that makes the most difficult things easy... there is no limit to what you can do with it. Just write pure JS or jQuery on top of it, to achieve your business logic.
Step 1. Create a file to hold the custom JS. As a convention, we recommend you split up the JS by entity name. For example, for a Product we recommend creating public/assets/js/admin/forms/product.js
.
Step 2. Load that script file in your CrudController, within setupCreateOperation()
or setupUpdateOperation()
, depending on when you want it loaded:
Widget::add()->type('script')->content('assets/js/admin/forms/product.js');
or
Widget::add()->type('script')->content(asset('assets/js/admin/forms/product.js'));
Step 3. Inside that JS file, use the CrudField JS Library to manipulate fields, in any way you want. For example:
crud.field('agree_to_terms').onChange(function(field) {
if (field.value == 1) {
crud.field('agree_to_marketing_email').show();
} else {
crud.field('agree_to_marketing_email').hide();
}
}).change();
Alternatively, since all action methods also accept a boolean
as a parameter, the above can also become:
crud.field('agree_to_terms').onChange(function(field) {
crud.field('agree_to_marketing_email').show(field.value == 1);
}).change();
Notice that we did three things here:
crud.field('agree_to_terms')
;.onChange()
;.change()
- that way, the closure will get evaluated first thing when the pageloads, not only when the first field actually gets changed;We've identified the most common ways developers need to add interaction to their forms. Then we've documented them below. That way, it's easy for you to just copy-paste a solution, then customize to your needs. You can also see these examples fully working, in our demo.
When a checkbox is checked, show a second field:
crud.field('visible').onChange(function(field) {
crud.field('visible_where').show(field.value == 1);
}).change();
When a checkbox is checked, show a second field and un-disable it, by chaining the action methods:
crud.field('visible').onChange(function(field) {
crud.field('displayed_where').show(field.value == 1).enable(field.value == 1);
}).change();
Alternatively, a more readable but verbose version:
crud.field('visible').onChange(function(field) {
if (field.value == 1) {
crud.field('displayed_where').show().enable();
} else {
crud.field('displayed_where').hide().disable();
}
}).change();
When a radio has something specific selected, show a second field:
crud.field('type').onChange(function(field) {
crud.field('custom_type').show(field.value == 3);
}).change();
When a select has something specific selected, show a second field:
crud.field('parent').onChange(function(field) {
crud.field('custom_parent').show(field.value == 6);
}).change();
function do_something() {
console.log('Displayed AND custom parent.');
}
crud.field('parent').onChange(field => {
if (field.value === 6 && crud.field('displayed').value == 1) {
do_something();
}
});
let do_something_else = () => {
console.log('Displayed OR custom parent.');
}
crud.field('displayed').onChange(field => {
if (field.value === 1 || crud.field('parent').value == 6) {
do_something_else();
}
});
crud.field('parent').onChange(field => {
if (field.value === 6 || crud.field('displayed').value == 1) {
do_something_else();
}
});
crud.field('parent').onChange(function(field) {
switch(field.value) {
case 2:
console.log('doing something');
break;
case 3:
console.log('doing something else');
break;
default:
console.log('not doing anything');
}
});
When a checkbox is checked, automatically check a different checkbox or radio:
crud.field('visible').onChange(field => {
crud.field('displayed').check(field.value == 1);
});
Create a slugged version of an input and put it into a second input:
let slugify = text =>
text.toString().toLowerCase().trim()
.normalize('NFD') // separate accent from letter
.replace(/[\u0300-\u036f]/g, '') // remove all separated accents
.replace(/\s+/g, '-') // replace spaces with -
.replace(/[^\w\-]+/g, '') // remove all non-word chars
.replace(/\-\-+/g, '-') // replace multiple '-' with single '-'
crud.field('title').onChange(field => {
crud.field('slug').input.value = slugify(field.value);
});
When multiple inputs change, change a last input to calculate the total (or average, or difference):
// Notice that we have to convert the input values from STRING to NUMBER
function calculate_discount_percentage() {
let full_price = Number(crud.field('full_price').value);
let discounted_price = Number(crud.field('discounted_price').value);
let discount_percentage = (full_price - discounted_price) * 100 / full_price;
crud.field('discount_percentage').input.value = discount_percentage;
}
crud.fields(['full_price', 'discounted_price']).forEach(function(field) {
field.onChange(calculate_discount_percentage);
});
When a select subfield has been selected, enable a second subfield:
crud.field('wish').subfield('country').onChange(function(field) {
crud.field('wish').subfield('body', field.rowNumber).enable(field.value == '');
});
When a checkbox is checked, disable all subfields in a repeatable and hide the repetable field entirely:
crud.field('visible').onChange(field => {
var subfields = $(crud.field('wish').input).parent().find('[data-repeatable-holder]').data('subfield-names');
// disable/enable all subfields
subfields.forEach(element => {
crud.field('wish').subfield(element).enable(field.value == 1);
});
// hide/show the repeatable entirely
crud.field('wish').show(field.value == 1);
}).change();
// this last change() call makes the code above also run on pageload,
// so that if the checkbox starts checked, it's visible,
// if the checkbox starts unchecked, it's hidden
When using the relationship
field on a morph relation, we can target the ID or TYPE inputs using brackets (the are not subfields):
crud.field('commentable[commentable_type]').onChange(field => {
// hide/show the other input
crud.field('wish').show(field.value == 'article');
}).change();
// this last change() call makes the code above also run on pageload
Then you'll love our premium add-ons - productivity tools and tons of new features.