Laravel 8 multi value select filtering - laravel

I'm trying to build Laravel project that will have a multi-select dropdown with list of categories. Selecting category should reload the page and apply filter.
"scopeFilter" in my model is actually doing filtering, but here i just need to find a way to properly form URL. The problem is that this code i have:
<form id="cats-form" action="#" method="GET">
<select multiple class="chosen-select" name="test[]">
#foreach($categories->get() as $cat) //this loop goes through existing categories in the system
#php
//if category is part of URL, pre-select it in the select:
$arr = request()->all();
$selected = '';
if(array_key_exists('test', $arr)) {
$testArr = $arr['test'];
$selected = in_array($cat->id, explode(',', $testArr)) ? 'selected' : '';
}
#endphp
<option {{ $selected }} value="{{ $cat->id }}">{{ $cat->name }}</option>
#endforeach
</select>
</form>
<script>
$(".chosen-select").chosen({ })
$('.chosen-select').on('change', function(evt, params) {
$('#cats-form').submit();
});
</script>
Is actually giving me this URL:
http://localhost:11089/?test%5B%5D=19&test%5B%5D=5
While i actually need this:
http://localhost:11089/?test=19,5
I guess it's a trivial problem to solve for someone with better knowledge of Laravel, can you tell me pls what i'm doing wrong here?

This is rather how the language or framework or library reads an URL query string. Assuming that your prefered way of URL string is a valid format (as I usually see the format ?arr[]=val1&arr[]=val2 and never see the second format that you preferred), both query string formats should be acceptable to PHP.
As Yarin stated that the best way PHP reads an array is the first method, you don't have to worry too much because the decoded URL query string is exactly in the first format.

Related

Livewire ignore does not receive correct data

I'm using selectize.js for dropdown styling with livewire. I'm using livewire for a data table with sortable columns and pagination. The issue is, every time I make pagination or a sort by column, the javascript goes missing thus, there's no styling for the dropdown. I've solved the styling issue using wire:ignore. Now the new problem that I have is that the data passed to the dropdown is not accurate.
#foreach($applications as $application)
<p>{{$application->status}}</p>
<div wire:ignore>
<select class="selectize" name="status" data-width="200px">
#foreach(['Pending',
'Hired',
'Under consideration'] as $status)
<option
#if($application->status === $status) selected #endif>{{ $status }}</option>
#endforeach
</select>
</div>
#endforeach
Inside the <p>{{$application->status}}</p> tag, I get the status 'Pending' but on the dropdown, it shows 'Hired'. The correct status is 'Pending'.
(from comment) #stalwart1014 for example, when I use "select2" I do this
in content section
<select id="select2" wire:model="some">
//.....
</select>
in script section
$(document).ready(function() {
window.initSelectDrop=()=>{
$('#select2').select2({
placeholder: '{{ __('Select') }}',
allowClear: true});
}
initSelectDrop();
window.livewire.on('select2',()=>{
initSelectDrop();
});
});
and in component
public function hydrate()
{
$this->emit('select2');
}
This not always function properly with JS element...but hope this can help you. Greetings
it's maybe a bit late, but worth to mention for the future, I will do not point directly to your issue but explain the workaround of wire:ignore, the wire:ignore directive ignores the updates or changes for the further requests and updates, this attributes is defined for playing with JS third party library, the wire:ignore directive prevent all it's nested elements from updating if you wish to except Childs from updating you can use wire:ignore.self directive

Problem accessing data with relations in Laravel

I want to create a multiple select option based on a parent select option. Here is what I have done to achieve this.
On my livewire php file:
public function updatedSelectedMajor($major_id) {
$this->skills = \App\Models\Major::where('major_id',$major_id)->with('mySkills')->get();
}
When I run this with this statement:
#foreach($skills as $skill)
<option value="$skill->mySkills">{{$skill->mySkills}}</option>
#endforeach
I get these results.
[{"skills_id":5,"name":"Digital Marketing","points":10,"created_at":null,"updated_at":null,"pivot":{"major_id":2,"skills_id":5}}]
With this I want to get only the skills_id as the value and name as the option name, but I'm getting error Property [name] does not exist. I tried with pivot, but it doesn't work either.
and when I do this:
<option value="$skill->mySkills[0]->skills_id">{{$skill->mySkills[0]->name}}</option>
it works fine, but I need to get all of the records, not just one.
Blade provides simple directives for working with PHP's loop structures. This directive functions identically to their PHP counterpart foreach, for example:
#foreach($skills->mySkills as $skill)
<option value="{{ $skill->id }}">{{ $skill->name }}</option>
#endforeach
join table
use \App\Models\Major;
public function updatedSelectedMajor($major_id)
{
$myvalue = $this->skills::join('major','major.id','major_id')
->where('major_id',$major_id)
->select('skills.*','major.myskills as myskills');
return $myvalue;
}
in blade
#foreach($skills as $item)
<option value="$item->skills_id">{{$item->mySkills}}</option>
#endforeach

How do I return an option saved to the Laravel database?

I am programming a system in Laravel 5.8 and nenessito do the editing of the user through a select but when I make the request does not appear the option that the user selected.
I already tried to pass the Controller attractive but not right.
public function edit($id)
{
$users = User::find($id);
$institutions = Institution::all('razaosocial');
return view('users.edit', compact(array('users','institutions')));
}
<div class="form-row">
<div class="col-md-6">
{{Form::label('Instituição:')}}
<select class=form-control name="instituicao" id="instituicao">
<option value="null">Selecione uma Instituição</option>
#foreach($institutions as $institution)
<option value="{{$institution->razaosocial}}">
{{ $institution->razaosocial}}
</option>
#endforeach
</select>
</div>
</div>
I hope that appears in the view the option selects by during registration.
Hoping something works in programming is very frustrating and I am at the moment. compact() actually creates an associative array whose keys are variable names and their corresponding values are array values. So instead of
compact(array('users','institutions'));
make it
compact('users','institutions');
Here is a reference that solves this problem
Laravel: Display data in DropDown from database

Dynamic dropdown in laravel 5.8

here's what i want to happened
- First dropdown (Parent)
- Second dropdown (Child)
- The options on the second dropdown will depend on the selected value of the first dropdown.
I am using laravel 5.8.
In Your view
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select class="form-control{{ $errors->has('state') ? ' is-invalid' : '' }}" onchange="dropdown(this.value);" name="state" id="state">
<option>--select state--</option>
<option value="Kerala">Kerala</option>
<option value="Karnataka">Karnataka</option>
<option value="Tamil Nadu">Tamil Nadu</option>
</select>
<select class="form-control{{ $errors->has('district') ? ' is-invalid' : '' }}" name="district" id="district">
<option>Please choose state from above dropdown</option>
</select>
<script >
function dropdown(msg){
var state=msg;
$.ajax({
url: 'getdistrict/'+state,
type: 'get',
dataType: 'json',
success: function(response){
$("#district").empty();
var len = 0;
if(response['data'] != null){
len = response['data'].length;
}
if(len > 0){
// Read data and create <option >
for(var i=0; i<len; i++){
var id = response['data'][i].id;
var name = response['data'][i].name;
var option = "<option value='"+name+"'>"+name+"</option>";
$("#district").append(option);
}
}
}
});
}
In your controller
public function district($id)
{
$userData['data'] = DB::table('alldistricts')
->where('state', $id)
->orderBy('name', 'asc')
->get();
echo json_encode($userData);
exit;
}
In your web.php
Route::get('/getdistrict/{id}','RegistrationController#district')->name('getdistrict');
To achieve this you must know front end script like Vue js or at least native javascript. I'll show how to achieve this using vue js and axios package and native js and ajax.
Vue js and axios:
Documentation:
1)https://vuejs.org (for vue js)
2)https://www.npmjs.com/package/axios (for axios package)
include this line in you header.
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
Note: I used Vue js cdn for development mode. Make sure to change to production mode on live. Check the documentation for further.
Then add this in the form:
<form method='post' action="http://example.com/location" id="developers">
<select name="developer_type" v-on:change="getLanguages" v-model="developerType">
<option disabled> Select Developer Type </option>
<option value="front"> Front-End Developer </option>
<option value="back"> Back-End Developer </option>
<option value="full"> Full Stack Developer </option>
</select>
<select name="Coding_language">
<option disabled v-if="developerType!=null"> Select Developer Type First </option>
<option disabled v-else="developerType!=null"> Select Coding Language </option>
<option v-for="lang in codingLaguanges" value="lang"> #{{lang}} </option>
</select>
</form>
Note: use #{{}} if only you use Laravel blade as your template engine Otherwise use only {{}}
Then add this on footer script
let developerForm = new Vue({
el:'#developers',
data:{
developerType:null,
codingLanguages:null
},
methods:{
getLanguages: function () {
axios
.post('/developers/getLanguages',{
type: developerForm.developerType
})
.then(response => (
developerForm.codingLanguages = response.data.languages
));
}
}
});
Note:I have used v-on:change and v-model in select instead of using watcher ands-model because this concept will be easier if you are new to vue js, Otherwise use Watcher itself. Check Vue js Documentation. However Both will work in this case.
In .post give you correct url to get result.
then define your route
Route::post('/developers/getLanguages', ['as'=>'dev.getLang','uses'=>'web\DevController#getLanguages']);
Note this is laravel part. you ca see Documentation in https://laravel.com
then in your DevController add this method
public function getLanguages(Request $request){
//do something to fetch result from db. Let us consider user has selected backend as developer type and there is array named Languages and it contains elements named php, python and java. i.e. $languages = ['php','python','java'].
return response()->Json(['languages'=>$languages],200);
}
Note: This will be your method for Controller to know detailed about controller check laravel documentation mentioned in previous note. Here you can retrieve the variable value from db also. but I used only sample values. In return I used array in json because you can n number of variables in that array(For example you can use statusCode to identify your error in future and much more.). Then make sure the name of the key in json array and name of the object in axios while retrieving is same. And I used status code as 200 because the browser take response of the request is successful. if you use 400 browser take response of the request is error.
This is the easiest method you can achieve.
You can also use jquery ajax and jquery or native javascript and javascript ajax to achieve this. But it has some complexity and limitation.
If you need code for native js or jQuery comment it and I will post it

Keeping select values across pages

I have a couple of routes
Route::get('/route_one', 'IndexController#index');
Route::get('/route_two', 'IndexController#index');
They call the same controller function because these pages need the same array of data. This function is as follows
public function index()
{
$user = Auth::user();
if( $user ) {
$fileData = $this->fillArrayWithFileNodes(new DirectoryIterator( public_path(). '/images'));
$currentPath= Route::getFacadeRoot()->current()->uri();
if(!empty($fileData)) {
return view('index', compact('fileData', 'currentPath'));
}
} else {
return view('auth.login');
}
}
Now the index view is pretty straight forward, but it does has this part
#if($currentPath == 'route_one')
#include('layouts.searchbarRouteOne')
#endif
#if($currentPath == 'route_two')
#include('layouts.searchbarRouteTwo')
#endif
So depending on what route is called, a different sidebar is displayed. Now the sidebars essentially contain a load of select inputs like the following
<div class="col-lg-3">
<div class="form-group">
<label>Year</label>
<select id="year" class="form-control">
<option value=""></option>
#foreach($fileData["route_one"] as $year => $products)
<option value="{{ $year }}">{{ $year }}</option>
#endforeach
</select>
</div>
</div>
Both sidebars have different selects. When select options are selected, an ajax call is made to display an image. This all works fine.
This is my problem. I have a link to get to route_one or route_two. As the page refreshes when the link is clicked, the selects are at their default state. What I would like to do somehow is keep the last state of the select inputs. I am not storing this data within a database which may be an issue?
Furthermore, route_two relies on the select options from route_one. So when route_two is selected, I need to pass it route_ones options.
What would be the best way to achieve what I am after?
Thanks
Think what you are trying to accomplish here: remember the old input values.
You could send the form when clicking the link and flash the data in your controller or use JavaScript saving input values to the browser's storage.
Simple example using plain JavaScript
// Get all select-elements
var inputs = document.querySelectorAll('select');
// Loop through them
for (var i = 0; i < inputs.length; i++) {
// Set the old input value
inputs[i].value = localStorage.getItem(inputs[i].name);
// Start listening changes
inputs[i].addEventListener('change', store);
}
// The function to call when the value has changed
function store(event) {
// Set the new value to the browser's storage
localStorage.setItem(event.target.name, event.target.value);
}
In that example your form elements are required to have unique name attributes. Of course it can be switched out using e.g. id attribute.

Resources