drop down select field stays null Livewire - dropdown

I'm trying out Livewire for the first time. The drop-down is populated from the database. Similar codes works for text fields, but fails with drop-down select fields.
Edit: The form is inside a bootstrap modal
Code is as below: The livewire component (leads-form.blade)
<div class="modal-content">
<form wire:submit.prevent="submit">
#csrf
<div class="input-field col s12">
<label for="role">Client</label>
<select class="error validate" wire:ignore id="client_id" wire:model="client_id">
<option disabled value=" ">Client</option>
#foreach($clients as $client)
<option value="{{$client->id}}"> {{$client->clientname}}</option>
#endforeach
</select>
</div>
<div class="input-field col m12 s12">
<input id="contactperson" type="text" name="contactperson" wire:model="contactperson" />
#error('contactperson') <span class="error"><small>{{ $message }}</small></span> #enderror
<label for="contactperson">Contact Person</label>
</div>
<div class="row">
<div class="row">
<div class="input-field col s12">
<button class="btn cyan waves-effect waves-light right" type="submit">Add
<i class="material-icons right">send</i>
</button>
</div>
</div>
</div>
</form>
</div>
Next Livewire leads class is as a below:
class LeadsForm extends Component
{
public $contactperson;
public $client_id;
public function submit()
{
Lead::create([
'client_id' => $this->client_id,
'contactperson' => $this->contactperson,
]);
Alert::toast('Client created successfully', 'success');
return $this->redirectRoute('leads.index');
}
public function render()
{
$clients = Client::all();
return view('livewire.leads-form',[
'clients'=>$clients,
]);
}
}
I'm using the laravel debugbar, and it shows the array client_id field as null.

Remove the wire:ignore in the select element, that avoid produce any Livewire event that can be wrapped to backend
<select class="error validate" wire:ignore id="client_id" wire:model="client_id">
<option disabled value=" ">Client</option>
#foreach($clients as $client)
<option value="{{$client->id}}"> {{$client->clientname}}</option>
#endforeach
</select>

Related

Button for update function not working laravel 8 (CRUD)

I'm new to laravel 8. I try to make an update function controller when user already edit their data and store it in database. I try to click submit button and it's not working without any reason when i try to inspect at chrome. So i try another way which is comment the $request->validate and it's only change for name data while organisation_id leave blank and return to NULL. I wonder do we need to always validate the data in update function ?
Here is my Controller
public function edit($id)
{
$record = User::find($id);
$org = Organisation::all();
$t = Organisation::pluck("name");
return view ('user.edit',compact('record','org','t'));
}
public function edit_store(Request $request, $id)
{
$request->validate([
'name' => 'required',
'organisation_id' => 'required',
]
);
$record= User::find($id);
$record->name = $request->name;
$record->organisation_id = $request->organisation_id;
$record->save();
return redirect ('user')->with('success', 'Thank you');
}
Here is my edit blade
<div class="card">
<div class="card-body">
<form action="{{route('user_edit_store1', $record->id)}}" method="POST">
#csrf
<input type="hidden" name="id" value="{{ $record->id }}">
<div class="form-group row">
<label for="name"
class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
<div class="col-md-6">
<input id="name" type="text"
class="form-control #error('name') is-invalid #enderror" name="name"
value="{{ old('name') ? old('name') : $record->name }}"
</div>
</div>
<div class="form-group row">
<label for="organisation_id"
class="col-md-4 col-form-label text-md-right">{{ __('Organisation') }}</label>
<div class="col-md-6">
{!! Form::open(['route' => 'user_store']) !!}
{!! Form::select('id', $t, 'id', ['class' => 'form-control']) !!}
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary" >
{{ __('Save') }}
</button>
</div>
</div>
</form>
</div>
</div>
Routes
Route::get('user_edit/{id}',[UserController::class,'edit'])->name('user_edit');
Route::post('user_edit_store/{user}',[UserController::class,'edit_store'])->name('user_edit_store1');
Model user.php
protected $fillable = [
'name',
'organisation_id',
];
It appears that the <select> that you're creating with the Form::select form helper will have name of 'id' instead of 'organisation_id' which will result in a validation fail.

Why are my single select lists converting to multi select lists on model binding?

I'm trying to bind multiple single select lists to one list of strings in my view model I have the property: public List<string> Items {get; set;} and in my view I have 3 select lists with single select option, but when I try to model bind my select list to Items property using asp-for="#Model.Items" all my single select lists converts to multi select lists. Why?
My view:
<form asp-controller="Admin" asp-action="Index" method="post">
<div class="col-12">
<div class="row">
<div class="form-group col-4">
<div class="d-inline-block">
<label>Order By Price:</label>
</div>
<div class="d-inline-block">
<select class="form-control" asp-for="#Model.Items" style="width:150px">
<option value="Ascending">Ascending</option>
<option value="Descending">Descending</option>
</select>
</div>
</div>
<div class="form-group col-4">
<div class="d-inline-block">
<label>Order By Name:</label>
</div>
<div class="d-inline-block">
<select class="form-control" asp-for="#Model.Items" style="width:150px">
<option value="A-Z">A-Z</option>
<option value="Z-A">Z-A</option>
</select>
</div>
</div>
<div class="form-group">
<div class="d-inline-block">
<button type="submit" class="btn btn-secondary">Confirm</button>
</div>
</div>
</div>
</div>
</form>
Controller:
[HttpPost]
public IActionResult Index(MangeProductsViewModel vm)
{
return View(new MangeProductsViewModel
{
Products = productRepository.Products.ToList().SortProducts(vm)
});
}
My viewmodel
public IEnumerable<Product> Products { get; set; }
public List<string> Items { get; set; }
And when I select items from lists it adds them correctly the problem is dat user can select multiple options from one list
That's because asp-for invokes a tag helper, and for a prop of type List<string>, the HTML that is generated is going to be a select multiple. However, this wouldn't work for you anyways as it would give all the selects the same name. As a result, they'll simply overwrite each other, not add to each other.
For this, you're going to have to handle things manually via:
<select name="Items[]">
#foreach (var option in Model.SelectList1Options)
{
<option value="#option.Value">#option.Text</option>
}
</select>
For each drop down.
Try this!
In your HttpGet method create a new list with length 3 and assign it to Items property of model and pass the model to view.
And in view write asp-for as follows
asp-for=“#Model.Items[0]”
asp-for=“#Model.Items[1]”
asp-for=“#Model.Items[2]”
The reason is that you have used asp-for="#Model.Items", sicne your item is type of List<string>, so the dropdown list is set as multiple select.
Just use name="Items" instead:
<form asp-controller="Managers" asp-action="SelectTest" method="post">
<div class="col-12">
<div class="row">
<div class="form-group col-4">
<div class="d-inline-block">
<label>Order By Price:</label>
</div>
<div class="d-inline-block">
<select class="form-control" name="Items" style="width:150px">
<option value="Ascending">Ascending</option>
<option value="Descending">Descending</option>
</select>
</div>
</div>
<div class="form-group col-4">
<div class="d-inline-block">
<label>Order By Name:</label>
</div>
<div class="d-inline-block">
<select class="form-control" name="Items" style="width:150px">
<option value="A-Z">A-Z</option>
<option value="Z-A">Z-A</option>
</select>
</div>
</div>
<div class="form-group">
<div class="d-inline-block">
<button type="submit" class="btn btn-secondary">Confirm</button>
</div>
</div>
</div>
</div>
</form>
Result:

How to get index of changed array under $watch in vuejs

I am using an array of objects
({"code":"id1","color":"red","description":"eg1"})
where each object contains input fields.User can dynamically add and remove those objects.
Now I want that when he enters code rest of the field should be filled automatically.
For that I have developed an algorithm which will take the code and will give me the color and description but for that I need the POSITION of the object which is changed so that I can update the array on that index itself.
Below is my share of code:
<div v-for="(x,i) in fabric_arr">
<!--<pre>{{x}}</pre>-->
<div class="row">
<div class="col-md-4">
<span>
<input type=”text” list="idOfDatalist" class="form-control border-input" placeholder="Fabric Code" v-model="x._id">
<datalist id="idOfDatalist">
<option v-for="y in all_fabrics">{{y._id}}</option>
</datalist>
</span>
</div>
<div class="col-md-4">
<span>
<input type=”text” class="form-control border-input" placeholder="Fabric Color" v-model="x.color"></span>
</div>
<div class="col-md-4">
<span>
<input type=”text” class="form-control border-input" placeholder="Fabric Description" v-model="x.description"></span>
</div>
</div>
</div>
And my controller:
watch: {
fabric_arr: {
handler : function (val) {
console.log("val");
console.log(val);
//val.color="red always";
this.fabric_arr[0].color="fghjkl"
},
deep: true
}
}
For all those who are looking for the answer,use v-bind:change() to trigger the changes and manipulate index there.
Below is the code:
<input type=”text” list="idOfDatalist" class="form-control border-input" placeholder="Fabric Code" v-model="x._id" v-bind:change="inpChangedForCode(x)">
<datalist id="idOfDatalist">
<option v-for="y in all_fabrics">{{y._id}}</option>
</datalist>

Using vue js with selectpicker

I'm using Vue.js to add multiple rows, each row contain two datetimepicker inputs and a bootstrap-select.
My problem is when I fill the inputs and click to add a new row the previous ones clear out, the reason is each time I add a new row I'm using setTimeout to referesh the selectpicker and the datetimepicker.
So I want to know if there is a way to trigger the last added element them without refreshing the previous ones.
Here is my code :
HTML
<div class="cols" id="app">
<ul style="list-style-type: none;">
<li>
<button style="float: right;margin-right: 20px;margin-top: 5px;" type="button" class="btn btn-success btn-xs" v-on:click="addRow()">
<i class="fa fa-plus"></i> Ajouter
</button>
</li>
<li v-for="(row, id) in rows">
<div class="form-inline cp-out" style="padding-bottom: 9px;border-radius:4px;background-color:white;margin-left:-20px;display:inline-block;width:100%;margin-top:10px;">
<div class="col-md-3">
<label :for="['time_start'+id]" class="control-label">start time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_start'+id]" data-link-format="hh:ii">
<input v-model="row.startTime" :name="'rows['+id+'][startTime]'" class="form-control" :id="['startTime' + id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-3">
<label :for="['time_end'+id]" class="control-label" style="margin-left:7px;">end time</label>
<div class="input-group date form_time" style="width:100%;" data-date="" data-date-format="hh:ii" :data-link-field="['time_end'+id]" data-link-format="hh:ii">
<input v-model="row.endTime" :name="'rows['+id+'][endTime]'" class="form-control" :id="['endTime'+id]" size="16" type="text" value="" >
<span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
</div>
</div>
<div class="col-md-4">
<div class="form-group select_group" style="margin-left:5px;">
<label :for="['status' + id]" class="control-label">Status</label>
<select data-width="100%" v-model="row.status" :name="'rows['+id+'][status]'" :id="['status' + id]" class="select_picker" data-live-search="true" multiple >
<option value="Status 1">Status 1</option>
<option value="Status 2">Status 2</option>
</select>
</div>
</div>
<div class="col-xs-1">
<button type="button" class="btn btn_delete btn-xs btn-danger" v-on:click="delRow(id)">
<i class="fa fa-remove"></i> delete
</button>
</div>
</div>
</li>
</ul>
</div>
JS
app = new Vue({
el: '#app',
data: {
rows: []
},
methods: {
addRow: function () {
this.rows.push({startTime: '', endTime: '', status: []});
setTimeout(function () {
$('.select_picker').selectpicker('refresh');
$('.form_time').datetimepicker({format: 'LT'});
}.bind(this), 10);
},
delRow: function (id) {
this.rows.splice(id, 1);
}
},created:function() {
this.addRow();
}
});
This is the example : https://jsfiddle.net/rypLz1qg/9/
You really need to write a wrapper component. Vue expects to control the DOM and not to have you making DOM-changing things like the *picker calls at arbitrary times. However, a component gives you the opportunity to tell your component how to interact with the DOM in each of its lifecycle hooks so that its behavior can be consistent. See the JavaScript tab on the wrapper component example page.

Vue.js not updating template when changing child objects

I'm extending laravel spark and wanted to try to validate registration before actually sending it off.
All data is handled nicely and correctly from the server but the errors do not pop-up.
The code being used for validation is as following:
module.exports = {
...
methods: {
...
validate(field, value) {
var formData = {
field: field,
value: value
};
var form = new SparkForm(formData);
Spark.post('/register_validate', form).then(response => {
this.registerForm.addSuccess(field);
}).catch(errors => {
this.registerForm.addError(field, errors[field]);
});
}
}
};
After, i extended SparkForm and added these methods (successes is just a copy of errors, used to display validation success messages):
/**
* SparkForm helper class. Used to set common properties on all forms.
*/
window.SparkForm = function (data) {
...
this.addError = function(field, errors) {
form.successes.remove(field);
form.errors.add(field, errors);
},
this.addSuccess = function(field) {
form.errors.remove(field);
form.successes.add(field, true);
}
};
And finally i added some methods on the SparkFormErrors.
/**
* Spark form error collection class.
*/
window.SparkFormErrors = function () {
...
this.add = function(field, errors) {
this.errors[field] = errors;
};
this.remove = function(field) {
delete this.errors[field];
}
};
In the console no errors are shown and in the network tab i can see the correct messages coming true, also when i add a console log in for example the response callback i can see the actual errors or success messages. But they are not drawn on screen.
For completeness i'll include the important content of the template blade file:
#extends('spark::layouts.app')
#section('content')
<spark-register-stripe inline-template>
<!-- Basic Profile -->
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
{{ trans('auth.register.title') }}
</div>
<div class="panel-body">
<!-- Generic Error Message -->
<div class="alert alert-danger" v-if="registerForm.errors.has('form')">
#{{ registerForm.errors.get('form') }}
</div>
<!-- Registration Form -->
<form class="form-horizontal" role="form">
<!-- Name -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('name')}">
<label class="col-md-4 control-label">{{ trans('user.name') }}</label>
<div class="col-md-6">
<input type="name" class="form-control" name="name" v-model="registerForm.name" autofocus #blur="validate('name', registerForm.name)">
<span class="help-block" v-show="registerForm.errors.has('name')">
#{{ registerForm.errors.get('name') }}
</span>
</div>
</div>
<!-- E-Mail Address -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('email')}">
<label class="col-md-4 control-label">{{ trans('user.email') }}</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" v-model="registerForm.email" #blur="validate('email', registerForm.email)">
<span class="help-block" v-show="registerForm.errors.has('email')">
#{{ registerForm.errors.get('email') }}
</span>
</div>
</div>
<!-- Password -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('password')}">
<label class="col-md-4 control-label">{{ trans('user.password') }}</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password" v-model="registerForm.password" #blur="validate('password', registerForm.password)">
<span class="help-block" v-show="registerForm.errors.has('password')">
#{{ registerForm.errors.get('password') }}
</span>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button class="btn btn-primary" #click.prevent="register" :disabled="registerForm.busy">
<span v-if="registerForm.busy">
<i class="fa fa-btn fa-spinner fa-spin"></i>{{ trans('auth.register.submitting') }}
</span>
<span v-else>
<i class="fa fa-btn fa-check-circle"></i>{{ trans('auth.register.submit') }}
</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</spark-register-stripe>
#endsection
Any bright mind seeing what i'm missing/forgetting?