I'm fairly new to Laravel (and I love it!) I'm trying to do something a bit complicated: Creating a drop-down menu that upon selection of an option -will display a second drop-down menu that will give further options dynamically based on the previous selection.
My controller looks like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Manufacturer;
use App\GearCategory;
use App\SubCategory;
use App\GearItem;
class GearItemController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function create(Manufacturer $manufacturers, GearItem $gearItem, GearCategory $gearCategory, SubCategory $subCategory)
{
// dd($gearCategory->all());
$catNum = 6; // <-- needs to be equal to the dispaly div name. Hard coded as 6 for test purposes.
$gearCategory = $gearCategory->all();
$subCategory = $subCategory::where('gear_categories_id', $catNum)->get();
$manufacturers = $manufacturers->all();
return view('gearitem.create', compact('gearCategory'), compact('subCategory'), compact('manufacturers'), compact('gearItem'));
}
}
My blade looks like this:
<div class="card-header">
<h3>Add a new gear Item</h3>
</div>
<div class="container">
<select name="gear_categories_id" id="gear_categories_id" class="custom-select mb-3 mt-3"
onchange="selector('display_div', this)">
<option value="" selected>Choose category</option>
#foreach ($gearCategory as $category)
<option id="cat_selector" value="{{ $category->id }}"
{{ (old("gear_categories_id") == $category->id ? "selected" : "") }}>{{ $category->name }}
</option>
#endforeach
</select>
</div>
<script>
"use strict"
function selector(divId, element) {
console.log(element.value);
document.getElementById(divId).setAttribute("name", element.value)
}
</script>
<div class="display_div container" id="display_div" name="">
<select name="sub_categories_id" id="sub_categories_id" class="custom-select mb-3 mt-3"
onchange="selector('display_div', this)">
<option value="" selected>Choose item's type</option>
#foreach ($subCategory as $scategory)
<option id="cat_selector" value="{{ $scategory->id }}"
{{ (old("sub_categories_id") == $scategory->id ? "selected" : "") }}>{{ $scategory->name }}
</option>
#endforeach
</select>
</div>
(Sorry for using vanilla JS i haven't gotten into Vue yet...) I'm trying to pass the name of the "display_div" onto the $catNum variable in the controller (set to "6" just to test if it works but should be set to whatever the user is choosing on the first dropdown) The values of the 'gear_categories_id' appear as a foreign key in the SubCategory model and if i'll manage to feed these values to the second dropdown it would work. I've been struggling for hours with it and I can't figure it out... Please help and sorry for being such a n00b.
You can use an AJAX request on change of the parent category drop-down to populate the subcategories. See the code below. I have added a second route to get subCategories for a specific categoryID.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Manufacturer;
use App\GearCategory;
use App\SubCategory;
use App\GearItem;
class GearItemController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function create(Manufacturer $manufacturers, GearItem $gearItem, GearCategory $gearCategory, SubCategory $subCategory)
{
// dd($gearCategory->all());
$catNum = 6; // <-- needs to be equal to the dispaly div name. Hard coded as 6 for test purposes.
$gearCategory = $gearCategory->all();
$subCategory = $subCategory::where('gear_categories_id', $catNum)->get();
$manufacturers = $manufacturers->all();
return view('gearitem.create', compact('gearCategory'), compact('subCategory'), compact('manufacturers'), compact('gearItem'));
}
public function getSubCategories($categoryID) {
return SubCategory::where('gear_categories_id', $categoryID)->get();
}
}
Route::get('/sub-categories/{categoryID}', 'GearItemController#getSubCategories');
<div class="card-header">
<h3>Add a new gear Item</h3>
</div>
<div class="container">
<select name="gear_categories_id" id="gear_categories_id" class="custom-select mb-3 mt-3"
onchange="selector('display_div', this)">
<option value="" selected>Choose category</option>
#foreach ($gearCategory as $category)
<option id="cat_selector" value="{{ $category->id }}"
{{ (old("gear_categories_id") == $category->id ? "selected" : "") }}>{{ $category->name }}
</option>
#endforeach
</select>
</div>
<script>
"use strict"
function selector(divId, element) {
console.log(element.value);
document.getElementById(divId).setAttribute("name", element.value);
fetch('/sub-categories/')
.then(res => res.json())
.then(subCategories => {
var options = subCategories.reduce( (opts, cat) =>
`${opts}<option value="${cat.id}">${cat.name}</option>`, "");
document.getElementById("sub_categories_id").innerHTML = `<option value="" selected>Choose item's type</option>${options}`;
});
}
</script>
<div class="display_div container" id="display_div" name="">
<select name="sub_categories_id" id="sub_categories_id" class="custom-select mb-3 mt-3"
onchange="selector('display_div', this)">
<option value="" selected>Choose item's type</option>
</select>
</div>
Related
I have a dual list box in my Laravel form and I want to get those values that are taken over to the right side. Currently, only 1 value gets taken over, but if a user picks 3 values over, I would like all 3 values to be stored in the database. Is there any way to do this?
My controller:
public function storesurvey(Request $request)
{
$energy = new Customer();
$energy->rank1 = $request->input('rank1');
$energy->comments = $request->input('comments');
$energy->save();
return redirect('/survey')->with('success', 'data added');
}
My view:
<div class="container">
<div class="jp-multiselect">
<div class="from-panel">
<select name="from[]" class="form-control" size="8" multiple="multiple">
<option value="1">Item 1</option>
<option value="2">Item 2</option>
<option value="3">Item 3</option>
<option value="4">Item 4</option>
<option value="5">Item 5</option>
</select>
</div>
<div class="move-panel">
<button type="button" class="btn-move-all-right btn-primary"></button>
<button type="button" class="btn-move-selected-right"></button>
<button type="button" class="btn-move-all-left"></button>
<button type="button" class="btn-move-selected-left"></button>
</div>
<div class="to-panel">
<select name="rank1" class="form-control" size="8" multiple="multiple">
</select>
</div>
</div>
<script>
$(".jp-multiselect").jQueryMultiSelection();
</script>
<hr />
<!-- 2 -->
</div>
Could someone explain why only one value gets taken over and how I can send all value that are present on the right.
To send multiple value from a select input (or checkboxs having the same name) you need to name the input with [] like you did in the select form[]
<select name="rank1[]" class="form-control" size="8" multiple="multiple">
Then in your controller, you need to treat it as an array.
Here i used a json incode to convert all rank1 values into a single value string of format json.
public function storesurvey(Request $request)
{
$energy = new Customer();
$energy->rank1 = json_encode($request->input('rank1'));
$energy->comments = $request->input('comments');
$energy->save();
return redirect('/survey')->with('success', 'data added');
}
Other Solution
You can also make this auto using Casting
-Customer.php
class Customer .....
{
protected $casts = [
'rank1' => 'array'
];
....
}
Then in your controller, you can assign an array to the attribute rank1 directly without converting it
public function storesurvey(Request $request)
{
$energy = new Customer();
$energy->rank1 = $request->input('rank1');
$energy->comments = $request->input('comments');
$energy->save();
return redirect('/survey')->with('success', 'data added');
}
currently i am having multiple textboxes and multple dropdowns inside the foreach loop with same id.i have tried to get the dropdown selected text on change to the relevant textbox. currently it works only for the first text box and first dropdown. what can be the reason?
Here is my code
<div class="child-name-col">
<div id="header-type" class="foodmenu-dispay-view-header headerbody clearfix">
#foreach ($showenMenus as $key => $element)
<div class="daily-col daily-col-200 reset-padding margin-right-20 parent-div">
<input type="text" id="newmeal" name="newmeal[]" value="{{ $element->food }}">
<input type="hidden" id="mealtime" name="mealtime[]" value="{{ $element->id }}">
<div class="col-md-12 margin-top-5 dropdown" style="padding-left: 0px; padding-right: 0px;">
<select id="dropdown" name="dropdown[]" class="form-control foodrecipe_item dropdown_item" >
<option value="">None</option>
#foreach ($meal_list as $element)
<option value="{{ $element->id }}">{{ $element->title }}</option>
#endforeach
</select>
</div>
</div>
#endforeach
</div>
javascript
$(document).ready(function () {
$("#dropdown option").filter(function () {
return $(this).val() == $("#newmeal").val();
}).attr('selected', true);
$("#dropdown").on("change", function () {
$("#newmeal").val($(this).find("option:selected").text())
});
});
Three ways you can approach this problem:
Use a .class instead of an #id.
Uniquely name each element.
A little of both...
This example is off the top of my head and is intended to point you to a possible solution. It may or may not work out-of-the-box.
<div class="child-name-col">
<div id="header-type" class="foodmenu-dispay-view-header headerbody clearfix">
#foreach ($showenMenus as $key => $element)
<div class="daily-col daily-col-200 reset-padding margin-right-20 parent-div">
<!-- Notice the unique id of these inputs -->
<input type="text" id="newmeal-{{$key}}" name="newmeal[]" value="{{ $element->food }}">
<input type="hidden" id="mealtime-{{$key}}" name="mealtime[]" value="{{ $element->id }}">
<div class="col-md-12 margin-top-5 dropdown" style="padding-left: 0px; padding-right: 0px;">
<!-- notice the unique id, and the data attribute -->
<select id="dropdown-{{$key}}" data-key="{{$key}}" name="dropdown[]" class="form-control foodrecipe_item dropdown_item" >
<option value="">None</option>
#foreach ($meal_list as $element)
<option value="{{ $element->id }}">{{ $element->title }}</option>
#endforeach
</select>
</div>
</div>
#endforeach
</div>
$(document).ready(function () {
// this observer will need to be changed. Left as exercise for the reader.
$("#dropdown option").filter(function () {
return $(this).val() == $("#newmeal").val();
}).attr('selected', true);
// using a class to observe. Needs to be something that isn't used elsewhere, though.
$(".foodrecipe_item").on("change", function () {
var key = $(this).data('key');
$("#newmeal-"+key).val($(this).find("option:selected").text())
});
});
I have an angularForm and a combobox which is filled with options from the database. I need to get the selected option and pass it to a function on button click
<div class="form-group">
<select class="form-control" formControlName="product" #product>
<option *ngFor="let product of products" [value]='product'>{{product.name}}</option>
</select>
</div>
<div class="form-group">
<button (click)="addFeature(name.value, description.value,product.value)" [disabled]="angForm.pristine || angForm.invalid" class="btn btn-primary">Add</button>
</div>
When I click the button and console.log product.value I get [object,object], how to fix this?
addFeature(name, description, product) {
console.log(product);
// this.featureservice.addFeature(name, description,product);
// this.router.navigate(['/features/index']);
// location.reload();
}
UPDATE
The values in the combobox are filled by:
ngOnInit() {
this.getProducts();
}
getProducts() {
this.productservice.getProducts().subscribe(res => {
this.products = res;
})
}
You are getting the whole object, if you need name or description , access it as
addFeature(name, description, product) {
console.log(product.name);
}
EDIT
You can use ngModel and access the variable directly
<select class="form-control" [(ngModel)]="selectedProduct" formControlName="product" #product>
<option *ngFor="let product of products" [value]='product'>{{product.name}}</option>
</select>
and you can access it as,
addFeature() {
console.log(this.selectedProduct);
}
Bind to ngValue instead value of the option tag:
<div class="form-group">
<select class="form-control" formControlName="product" #product>
<option *ngFor="let product of products" [ngValue]='product'>{{product.name}}</option>
</select>
</div>
See Differences between value and ngValue in Angular 5 for more info.
I don't get your doubt precisely but try to change your select tag to something like so:
<select class="form-control" formControlName="product" #product>
<option *ngFor="let product of products" [value]='product.value'
{{product.name}}
</option>
</select>
I found the solution myself
<select class="form-control" [(ngModel)]='selectedOption' formControlName="product" #product>
<option *ngFor="let product of products" [ngValue]='product'>{{product.name}}</option>
</select>
<button (click)="addFeature(name.value, description.value,selectedOption.name)" [disabled]="angForm.pristine || angForm.invalid" class="btn btn-primary">Add</button>
Howdie do,
I'm attempting to only display an option if the code that the client used to login, matches the $scope.code in the controller.
The HTML should then display the option that matches the code the client logged in with.
View:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<div ng-if=" 'group' == 'code' ">
<option value="{{ group }} ">{{ msg }}</option>
</div>
</select>
</div>
Controller:
$scope.code = dataFactory.getCode();
$scope.codes = {
'ABC': 'First option',
'DEF': 'Second option'
}
There should only be one option showing as a client can't login with more than one code at a time
However, when I run this, I keep getting two input boxes instead of just the one that matches the code.
Is there something I'm missing here?
* UPDATE *
I've updated the code to the following and multiple options are still being printed:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<div ng-if=" group == code ">
<option value="{{ group }} ">{{ msg }}</option>
</div>
</select>
</div>
* UPDATE *
#ieaglle Removing the div allowed the if statement to excecute. The updated HTML is now:
<div class="">
<select id="customer-dd" ng-model="selectedCustomer" ng-repeat="(group, msg) in codes">
<option value="">select...</option>
<option ng-if=" group == code " value="{{ group }} ">{{ msg }}</option>
</select>
</div>
THANKKKK UUUU!!!
Try using ng-options instead with a filtered object.
http://jsfiddle.net/joshdmiller/hb7lu/
HTML:
<select ng-model="selectedCustomer" ng-options="msg for (group, msg) in filterObjsByProp(codes)"></select>
JS:
$scope.code = 'ABC';
$scope.codes = {
'ABC': 'First option',
'DEF': 'Second option'
};
$scope.filterObjsByProp = function (items) {
var result = {};
angular.forEach(items, function (value, key) {
if (key === $scope.code) {
result[key] = value;
}
});
return result;
}
Although this is overkill, since an object cannot have multiple properties with the same name, so you will only ever have 1 option in the select. As such, maybe a select is not the best option here, or maybe an array with key/value objects is better.
Change your HTML to this.
Notice the change in the ng-if statement.
<div class="">
<select id="customer-dd" ng-model="selectedCustomer">
<option value="{{ group }}" ng-repeat="(group, msg) in codes">select...
<div ng-if=" group == code ">
{{ msg }}
</div>
</option>
</select>
</div>
So I am trying to create a dropdown that loops through $countries and then the selected country is written to $country in the database under the user table. I got the dropdown, but it returns a null value to the database (well the validation at least).
Here is the call for the dropdown
<div class="form-group col-lg-6 col-sm-12">
<label for="country">Country</label>
<div id="countrydd">
#if(isset($currentCountry->name))
<select name="country" id="country_display" class="current-value-da-select closed">
{{(isset($user->country->name))?$user->country->name:$currentCountry->name}}
#foreach($countries as $country)
<option value="{{$country->name}}">{{$country->name}}</option>
#endforeach
</select>
#else
<select name="country" id="country_display" class="current-value-da-select closed">
{{(isset($user->country->name))?$user->country->name:'Select your Country'}}
#foreach($countries as $country)
<option value="{{$country->name}}">{{$country->name}}</option>
#endforeach
</select>
#endif
And this is the Javascript for the dropdown
//Country Drop Down
$('#countrydd').click(function(e) {
var selectWrapperCountry = $('#countrydd');
var currentValueCountry = $(this).find('a').html();
selectWrapperCountry.find('.current-value-da-select').html(currentValueCountry);
selectWrapperCountry.find('#country').val(currentValueCountry);
updateCarretClassCountry();
});
$('#countrydd a.current-value-da-select').click(function() {
updateCarretClassCountry();
});
function updateCarretClassCountry(){
if($('#countrydd a.current-value-da-select').hasClass('closed')) {
$('#countrydd a.current-value-da-select').attr('class', 'current-value-da-select opened');
}
else
{
$('#countrydd a.current-value-da-select').attr('class', 'current-value-da-select closed');
}
};
Any help to get the value to update right would be awesome.
It seems that you are using the select tag wrong. Select needs to have a name (that is what you will get as a post variable), and every option needs to have a value. So it would be something like this:
<select name="country">
<option value="1">First one</option>
<option value="2">Second one</option>
</select>
After the form is submitted, you would have
echo $_POST["country"]; //This will output 1 if First one is selected and 2 if Second one is
Also, why do you have <a> inside <option> ?
Read more at: http://www.w3.org/wiki/HTML/Elements/select