user1332738 user1332738 - 2 months ago 9
jQuery Question

Populating new select after choosing another select

I have a select which the user can select some Areas.

After choosing this area I want to populate a new select with subjects.

1 Area has n subjects.

But I am passing my data on the controller, and I don't know how to get this subjects from the database after changing my select, without submiting the form.

In my controller I have this method to pass the areas:

$areas = Areas::all();
$vars = array(
'url'=>$this->url,
'areas'=>$areas->pluck('name','idArea'),
);
return view($this->viewRoute.'.create')->with($vars);


I have the relation subjects() in my model which return this:

public function subjects(){
return $this->hasMany(Subjects::class);
}


this is my view:

<div class="form-group">
@if( !empty($areas['name']))
{{Form::label('select_area', $areas->name, array('class' => 'awesome')) }}
{{Form::hidden('areaId',$areas->idArea)}}
@else
{{Form::label('select_area', 'Selecionar Area', array('class' => 'awesome')) }}
{{Form::select('areaId',$areas,null,array('id'=>'select_area'))}}
@endif
</div>


and this is the jquery to populate the new select

<script>
jQuery(document).ready(function($){
$('#select_area').change(function(){
alert(this.value);
});
});
</script>


I can't get the data from the database with the value in the js function, so what would be the way to getting the subjects from my database?

Thanks for the help

Answer

There are a few ways depending on what you like.

AJAX

This requires you to create a new route which will take an area and return an array of subjects. What controller/method responds to this is up to you.

Route::post('getSubjects', ['uses' => 'SomeController@someMethod']);

Then in the someMethod function, you want to grab the list of subjects and return them as json so that you can parse it with javascript.

public function someMethod(Request $request)
{
    $area = App\Area::with('subjects')->find($request->get('id'));

    return response()->json($area->subjects);
}

Then where you have your alert in your javascript, you want to use jquery's ajax method to grab this data...

$.ajax({
    method: 'post',
    url: '/getSubjects',
    data: {
        id: $('#select_area').find('option:selected').val()
    },
    success: function(response) {
        // First we should clear out all the current subjects, otherwise we will just keep appending them.
        $('#select_subject').find('option').remove();
        $.each(response, function(i, subject) {  // This loops through the areas json returned from your controller
            $('#select_subject').append(  // This is jquery speak for adding a new child element to your subject dropdown.  (I guessed the select_subject id.)
                $('<option />').val(subject.id).text(subject.name)  // This is jquery speak for creating a new option element.  (I guessed your id column for the subject and the name column for the subject.  These depends on your database columns)
            );
        });
    }
});

Non AJAX

This way is probably easier on the performance because everything is done up front.

In your controller, instead of returning a list of areas, return a list of areas w/ their subjects, convert it to JSON, and drop it in a meta element.

$areas = Area::with('subjects')->get();

Then in your view, add a meta tag with the areas...

<meta name="areas" content="{{ $areas->toJson() }}" />

Now the page has all the data so there will be no need for additional queries. We just need to grab the correct subjects based on the area id.

var areas = $.parseJSON( $('meta[name="areas"]').attr('content') );
var subjects = areas[ $('#select_area').val() ];

$.each(subjects, function(i, subject) {
     .... // same code as last each loop in ajax section.
});