Reputation: 369
I have a Customer fiels that is dependent on a Project field.
In my form, I have a dropdown for project, and I need my second dropdown of customers to change dynamically according to the project.
I find the solution in a few places on the web, but the array doesn't change.
Can anyone help with this?
My form:
$dataProject=ArrayHelper::map(Project::find()->asArray()->all(), 'id', 'name');
echo $form->field($model, 'project_id')->dropDownList($dataProject,
['prompt'=>'-Choose a Project-',
'onchange'=>'
$.post( "'.Yii::$app->urlManager->createUrl('customer/lists?id=').'"+$(this).val(), function( data ) {
$( "select#title" ).html( data );
});
']);
$dataPost=ArrayHelper::map(Customer::find()->asArray()->all(), 'id', 'first_name');
echo $form->field($model, 'customer_id')
->dropDownList(
$dataPost,
['id'=>'title']
);
Code in the Customer controller:
public function actionLists($id) {
$countPosts = Customer::find()
->where(['project_id' => $id])
->count();
$posts = Customer::find()
->where(['project_id' => $id])
->orderBy('id DESC')
->all();
if($countPosts>0) {
foreach($posts as $post){
echo "<option value='".$post->id."'>".$post->first_name."</option>";
}
}
else{
echo "<option>-</option>";
}
}
Upvotes: 1
Views: 929
Reputation: 23738
So far the best way to add the dropdown options to the select when you have the access to jquery is to use .each()
but you need to provide the options from the controller/action
as json
rather than creating the html and then adding the html to the dropdown.
Then you are using $.post
and adding query string with the url
for the id
whereas you can use the data
option to send the id
.
Change your onchange
function to the following
'onchange'=>'
$.post( "'.Yii::$app->urlManager->createUrl('/customer/lists').'", {id:$(this).val()},function( data ) {
//this will clear the dropdown of the previous options
$("#title").children("option").remove();
//optionally you can use the following if you have a placeholder in the dropdown so that the first option is not removed
//$("#title").children("option:not(:first)").remove();
$.each(data, function(key, value) {
$("#title")
.append($("<option></option>")
.attr("value",key)
.text(value));
});
});
Then you are querying 2 times to the Customer
table once for count all records and one for all the lists of customers
$countPosts = Customer::find()
->where(['project_id' => $id])
->count();
$posts = Customer::find()
->where(['project_id' => $id])
->orderBy('id DESC')
->all();
you can simply query for the customers and use php:count()
function on the result set $posts
to count the total number of records.
$posts = Customer::find()
->where(['project_id' => $id])
->orderBy('id DESC')
->all();
$countPosts = count($post);
But we are not going to need the count
anyway this was just for information, change your action actionLists()
to below and remove the parameter $id
now as we are sending the id with post
.
public function actionLists() {
//set the response format to JSON
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
//get the id
$id = Yii::$app->request->post ( 'id' );
$posts = Customer::find ()
->where ( [ 'project_id' => $id ] )
->orderBy ( 'id DESC' )
->all ();
return ArrayHelper::map ( $posts , 'id' , 'first_name' );
}
Apart from doing all the above you should get used to of using available resources in form of extensions or plugins that are widely available one of them is Kartik/DepDropdown
which does the same thing with a lot of less pain of writing the javascript and just providing data from server-side.
Upvotes: 2