Access CRUD subfields via Javascript

In a previous tutorial, I talked about the CrudField JavaScript Library. I presented an example on how to change one field as the user...

Karan Datwani
Karan Datwani
Share:

In a previous tutorial, I talked about the CrudField JavaScript Library. I presented an example on how to change one field as the user types in another field - live, as they do it.

In this tutorial, I will show another frequent use case, asked by a Backpack user: How do you create a total field, thats sums up inputs in the repeatable? In order to do that, you need to learn:

  • How to access rows and their subfields?
  • How to get the count of rows?
  • How to alter row's field value?

Let's find the answer of these questions. There's no better way than an example - let's see some code!

CrudField On Subfields

Our user loved that in our demo, we have an Invoice CRUD. Great for adding multiple items to the invoice. But something is missing here - it does not show live subtotal and total while the user makes inputs. The user expects to see the subtotal and total before saving.

You got the idea now! Let's change the CRUD a bit to get it to function like this.

  1. First, I add a field to display the total and a subfield to display the row subtotal;
+CRUD::field('total')
+    ->size(2)
+    ->attributes(['readonly' => 'readonly', 'disabled' => 'disabled'])
+    ->prefix('$');
CRUD::field('items')
    ->subfields([
        [
            'name' => 'description',
            'type' => 'text',
            'wrapper' => [
                'class' => 'form-group col-md-7',
            ],
        ],
        [
            'name' => 'quantity',
            'type' => 'number',
            'attributes' => ['step' => 'any', 'min' => 0],
            'wrapper' => [
                'class' => 'form-group col-md-1',
            ],
        ],
        [
            'name' => 'unit_price',
            'type' => 'number',
            'prefix' => '$',
            'attributes' => ['step' => 'any', 'min' => 0],
            'wrapper' => [
                'class' => 'form-group col-md-2',
            ],
        ],
+        [
+            'name' => 'subtotal',
+            'type' => 'number',
+            'prefix' => '$',
+            'wrapper' => ['class' => 'form-group col-md-2'],
+            'attributes' => ['readonly' => 'readonly', 'disabled' => 'disabled'],
+        ],
    ])
    ->reorder('order');
  1. Now I create a file public/assets/js/admin/forms/invoice.js to put the form related javascript code. I use Script Widget to include the javascript file to the CRUD form;
+ use Backpack\CRUD\app\Library\Widget;

protected function setupCreateOperation()
{
+  Widget::add()
+        ->type('script')
+        ->content(asset('assets/js/admin/forms/invoice.js'));

 // Reset of the code

}

Now, the Magic Code

Yes, the invoice.js code.

  • I attach the following on the onChange event of quantity and unit_price field. This updates the subtotal on the row:
['quantity', 'unit_price'].forEach((name) => {
    crud.field('items').subfield(name).onChange(updateSubTotal);
});

function updateSubTotal(current_field) {
    const other_field = current_field.name === 'quantity' ? 'unit_price' : 'quantity';

    // Get the current rowNumber
    // and the value of the other field from the row
    const other_field_value = crud.field('items').subfield(other_field, current_field.rowNumber).input.value;

    // Calculate and update the subtotal field of the row
    var subtotal = current_field.input.value * other_field_value;
    crud.field('items').subfield('subtotal', current_field.rowNumber).input.value = subtotal;

    // Finaly update the total field
    updateTotal();
}

  • Now let's write some to update the total field, counting each row:
// Attach event to 'items' row addition or removal
crud.field('items').onChange(function (field) {
    updateTotal();
});

function updateTotal() {
    var total = 0;
    $total_rows = crud.field('items').wrapper.find('.repeatable-element').length;

    for (var row = 1; row <= $total_rows; row++) {
        var subtotal = parseFloat(crud.field('items').subfield('subtotal', row).input.value);
        total += subtotal;
    }

    crud.field('total').input.value = total;
}

Thats it! You can see it working now.

I hope you find this tutorial easy and helpful. CrudField JavaScript Library helps you build complex features like this one, without writing all the Javascript yourself. Let me know if there is something on which you want to see a guide. I'll try to come up with that!

Thanks for reading and using Backpack :)

Want to receive more articles like this?

Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.

Reactions & Comments

What do you think about this?

Latest Articles

Wondering what our community has been up to?