0

I am successfully updating a database using Vue 2 to a Laravel 8 Controller using Axios. However, I am stuck when attempting to pass an integer to my database.

My database has a column, 'number_of_searches' and it must be an integer.

Laravel Migration looks like this:

$table->integer('number_of_searches')->nullable();

And the model looks something like this:

class Product extends Model
{
    protected $fillable = [
        'product_title', 
        'number_of_searches' => 'integer',
    ];
}

My Vue updateProduct() function used FormData and appends the values coming from the form. It looks like this:

updateProduct(product){
   let data = new FormData();
   data.append('_method', 'PATCH');
   data.append('product_title', product.product_title);
   data.append('number_of_searches', product.number_of_searches);
   axios.post('/api-route-to-update/product_id/', data)
   .then(function (response) {
      console.log(response);
      })
   .catch(function (error) {
      console.log(error);            
       });
}

My update controller looks like this:

public function update(Request $request, $product_id){
   $product = Product::findOrFail($product_id);
   $product->update($request->all());
   $product->save();
}

I can have as many input fields as I need and it works perfectly as long as they are strings. However, when I use a number input field in my component such as:

<input v-model="product.number_of_searches" type="number" min="1" max="999">

The generated json that will pass from axios into my controller looks like this:

{ "id": 5, "product_title": "The Product Title will work great", "number_of_searches": "222"}

You will notice that 'number_of_searches' is passed as a string, hence my database fails because it is the wrong datatype, it requires an integer. After reading the documentation and other threads, it seems that FormData will always return strings and that I must just deal with this on the server side.

So what I did is, I went into my back-end updateProduct() method and attempted to modify the Request.

First I tried a few methods such as:

//this one
$requestData = $request->all();
$requestData['number_of_searches'] = 123;

//also this one
$request->merge(['number_of_searches' => 123]);

//and this
$data = $request->all();
$data['number_of_searches'] = 123;

After countless hours, I am unable to modify the original request. After doing some research, it seems that requests are protected and cannot be modified, which makes sense. Therefore I attempted to create a new request that clones $request->all(), like this:

$new_request = new Request($request->all());
$new_request->merge(['number_of_searches' => 123]);

But I have failed to force to override 'number_of_searched'

My question is:

Should I stay away from FormData completely in this case? What method do you suggest to pass forms that have integers or floats or other datatypes through axios or fetch? Or what am I doing wrong? I find it hard to believe that FormData would only send strings (making parseInt useless before using axios). I'm sure I am doing something wrong from origin.

On the other hand, maybe I need to completely change my approach in my Controller when receiving the data. I am working on an app with a lot of fields and I love $request->all() because it simplifies what I am trying to do. I wouldn't mind using intval on the server side and that's it, but it seems overly complicated.

1 Answer 1

1

On the Vue side, you can use the number modifier on v-model to make sure it's not casting the value to a string:

v-model.number="product.number_of_searches"

On the request side, you can use $request->merge to override the value in a request

$request->merge([
  'number_of_searches' => (int) $request->get('number_of_searches');
]);

At the model side in the updating hook within the boot method you can ensure the value is being casted as an int when saving:

static::updating(function ($model) {
    $model->number_of_searches = (int) $model->number_of_searches;
});

This should give you the end to end.

Sign up to request clarification or add additional context in comments.

2 Comments

Your code has definitely gotten me closer. The database is now updating the 'number_of_searches' column, however, it saves a 0 every time. I believe that the merge is still not happening. Two things are successful: v-model.number is now returning a json with an integer and not a string, which is exactly what I needed (if attempting this insert without the rest of your code, the database is still Null). If I use the booted method without updating the controller (merging), it still inserts a 0. It seems that the booted method forces a zero default, so I am certain the merge is the problem.
I have figured it out. I ditched the merge at the controller completely. I used the botted method you suggested as well as updated the input to be v-model.number. The other issue I needed to fix is that at the Product model I changed 'number_of_searches' => 'integer' to 'number_of_searches'. I wonder why this integer declaration inside $fillable would cause an issue when the JSON is already sending an integer. Thanks so much for helping me figure this out!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.