Feedback

Updating Data

# Loading Model

To see how we can load an existing entity's data let's create a very simple user profile form:

<?php

namespace App\Forms;

class UserForm extends \Laraform
{
  public $model = \App\User::class;

  public function schema() {
    return [
      'name' => [
        'type' => 'text',
        'label' => 'Name'
      ],
      'email' => [
        'type' => 'text',
        'label' => 'Email'
      ]
    ];
  }

  public function buttons() {
    return [[
      'label' => 'Submit'
    ]];
  }
}

If you are having a fresh Laravel install, you should have the User model along with the migration. If you haven't run the migrations yet, let's do it know, so we have the users table where we'll save data and load from later.

Create a route at routes/web.php and assign the form, that will load user dynamically data by id:

Route::get('/user/profile/{id}', function($id){
  return view('user.profile', [
    'form' => app('App\Forms\UserForm')->load($id)
  ])
})

Next, create a user in database with id = 1. Now if you render the form at /user/profile/1, you can see that the data for that user will be loaded.

#Updating Model

If you submit the form from the previous example you'll notice that it will add a new record to the database instead of updating it. This is because Laraform does not know if it should update anything, only that it should load some data. This is the data the backend receives on a request:

{
  // ...
  data: {
    name: 'John Doe',
    email: 'john@doe.com'
  }
}

To change this, let's add id element as key to the element list:

public function schema() {
  return [
    'id' => [
      'type' => 'key'
    ],
    'name' => [
      'type' => 'text',
      'label' => 'Name'
    ],
    'email' => [
      'type' => 'text',
      'label' => 'Email'
    ]
  ];
}

Now if you change the data of a loaded form and submit again, it will be updated in the database, because now it has the record's primary key and if that one is filled it means the record should be updated. The request looks like this this time:

{
  // ...
  data: {
    id: 1,
    name: 'John Doe',
    email: 'john@doe.com'
  }
}
If an entity's primary key eg. id is presented among the elements as key type Laraform will know to update the related model's entity instead of insert if that field has a value.

Keeping Primary Key Secret

By setting secret to true on the key element you can keep ID encoded when being sent to the frontend:

'id' => [
  'type' => 'key',
  'secret' => true
]

Now if you APP_ENV is set to something else than local you'll notice that the value of id element will be a short encoded string instead of the actual numeric value:

{
  // ...
  data: {
    id: 'yLA6m0oM',
    name: 'John Doe',
    email: 'john@doe.com'
  }
}

Changing Primary Key

If you need a different primary key than id you can change it by setting primaryKey property:

class UserForm extends \Laraform
{
  public $primaryKey = 'user_id';

  // ...
}

#Auto-Update

Let's see another example, where we have exactly the same form, except we don't load any data this time.

Add another route to our routes/web.php that just renders passes over the form without loading:

Route::get('/user/profile', function(){
  return view('user.profile', [
    'form' => app('App\Forms\UserForm')
  ])
})

When you render and submit the form the first time you can see that the following request will be sent:

{
  // ...
  data: {
    id: null,
    name: 'John Doe',
    email: 'john@doe.com'
  }
}

As we have an empty id on the first submission a new record will be inserted to the database. Let's check out the response we received:

{
  status: "success",
  messages: [],
  payload: {
    updates: {
      id: 3
    }
  }
}

As you can see the payload has updates which instructs Laraform to update its data accordingly.

So if you stay on the same page and submit the form again, id will be sent along with the user data because that was set from payload.updates:

{
  // ...
  data: {
    id: 3,
    name: 'John Doe',
    email: 'john@doe.com'
  }
}

This time Laraform will update the data based on id instead of inserting a new record.

If you send an updates object in the response's payload property that will instruct Laraform to update its data accordingly. This is true for any data not just IDs.

#Loading Manually

Chances are you don't always want to use a model assigned to a form, but you'd rather take care of handling the data yourself. To demonstrate this use case let's create a similar form, but without the User model assigned to it:

<?php

namespace App\Forms;

class UserForm extends \Laraform
{
  public function schema() {
    return [
      'id' => [
        'type' => 'key'
      ],
      'name' => [
        'type' => 'text',
        'label' => 'Name'
      ],
      'email' => [
        'type' => 'text',
        'label' => 'Email'
      ]
    ];
  }

  public function buttons() {
    return [[
      'label' => 'Submit'
    ]];
  }
}

Next, create a route to render the form at routes/web.php where we'll load the user's data manually:

Route::get('/user/profile/{id}', function($id){
  $user = \App\User::find($id);

  $data = [
    'id' => $user->id,
    'name' => $user->name,
    'email' => $user->email
  ];

  return view('user.profile', [
    'form' => app('App\Forms\UserForm')->load($data)
  ])
})
The load() method accepts either an ID of the assigned model or a set of data as array.

If you render the form you'll notice that it does nicely load our user data. But what happens if we submit? Nothing at all. This is because we haven't defined the processing logic to our form. Let's do that now.

#Updating Manually

We've already seen how we can rely on hooks to perform custom data processing in Submitting Data chapter. We're going to use the same method here.

Extend the form with an after hook and put processing logic there:

class UserForm extends \Laraform
{
  public function schema() {
    // ...
  }

  public function buttons() {
    // ...
  }

  public function after() {
    // Retrieving or creating a new user model
    $user = \App\User::findOrNew($this->data['id']);

    // Setting user data
    $user->name = $this->data['name'];
    $user->email = $this->data['email'];

    // Saving user model
    $user->save();
  }
}

Now visit /user/profile/1 for example and notice that when you submit the form it will actually update the user data.

#Loading & Updating On Frontend

By default Laraform takes care of loading the data on the backend if it is loaded on the backend as we've seen previously. Let's see what methods we can rely on to load and update data manually on the frontend.

#Loading Form Data

If you want to load data once the form is rendered you can use .load(data) method:

<script>
  export default {
    mixins: [Laraform],
    data() {
      return {
        schema: {
          name: {
            type: 'text',
            label: 'Name'
          }
        }
      }
    },
    mounted() {
      this.load({
        name: 'John Doe'
      })
    }
  }
</script>

The .load(data) method is used to load a complete set of data, meaning anything that is not contained in the provided data object will be emptied.

Let's see an example for that:

<script>
  export default {
    mixins: [Laraform],
    data() {
      return {
        schema: {
          name: {
            type: 'text',
            label: 'Name'
          },
          type: {
            type: 'radiogroup',
            label: 'Type',
            items: {
              'individual': 'Individual',
              'business': 'Business'
            },
            default: 'individual'
          }
        }
      }
    },
    mounted() {
      this.load({
        name: 'John Doe'
      })
    }
  }
</script>

When this form is created we only load name to it and everything else will be emptied. In this case name will be set to John Doe and type to null even though it has a default value.

#Updating Form Data

If you don't want other values to be set to default state you can use .update(data) method:

mounted() {
  this.update({
    name: 'John Doe'
  })
}

This will leave everything else untouched and only update what is contained withing the data object.

#Updating Element Data

You can use the form's .el$(path) method to reach certain elements within the form. You can use this to update only certain elements' data instead of the whole form's:

mounted() {
  this.el$('name').update('John Doe')
}
Note that the .el$() method will only return elements after the form is mounted because it is using refs to reach elements. If you need to reach it before mounted make sure you use $nextTick. The same is true for the form's .update() and .load() methods.

Example of using different methods in created hook with $nextTick:

created() {
  this.$nextTick(() => {
    // Load form data
    this.load({
      name: 'John Doe'
    })

    // Update form data
    this.update({
      name: 'John Doe'
    })

    // Update element data
    this.el$('name').update('John Doe')
  })
}