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 theusers
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 time:
{
// ...
data: {
id: 1,
name: 'John Doe',
email: 'john@doe.com'
}
}
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.
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)
])
})
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')
}
.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')
})
}