How to save data in model using Yii2 grid with Editable column - ajax

Can anyone help on editable column in gridview.I am using Yii2 and stuck with it.
I can't save data in my model.I can post from gridview column.
In my grid view:
$gridColumns= [
'patient_no',
'category_name',
'sdv_text',
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'sdv_status',
'pageSummary' => true,
'editableOptions'=> [
'header' => 'profile',
'format' => Editable::FORMAT_BUTTON,
'inputType' => Editable::INPUT_DROPDOWN_LIST,
'data'=> $StatusList,
]
],
// 'date_sdv_performed',
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'date_sdv_performed',
'editableOptions' => [
'header' => 'Date Sdv Performed',
'inputType'=>\kartik\editable\Editable::INPUT_WIDGET,
'format'=>\kartik\datecontrol\DateControl::FORMAT_DATE,
'widgetClass'=> 'kartik\datecontrol\DateControl',
],
],
[
'class' => 'kartik\grid\EditableColumn',
'attribute'=>'comments',
'hAlign' => 'top',
'vAlign' => 'middle',
'width'=>'100px',
'headerOptions' => ['class' => 'kv-sticky-column'],
'contentOptions' => ['class' => 'kv-sticky-column'],
'pageSummary' => true,
],
];
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout'=>"{items}\n{pager}",
'pjax'=>true,
'toolbar' => [
'{export}',
'{toggleData}'
],
'responsive'=>true,
'hover'=>true,
'columns' => $gridColumns
]);
In my controller action:
public function actionMonitoring($site_name)
{
$this->layout = 'sdv-carolina-main';
$Countries = new Countries;
$model = new Flagging;
$searchModel = new FlaggingSearch();
$dataProvider = $searchModel->monitoringsearch($site_name);
$allocatedsites = new AllocatedSites;
if (Yii::$app->request->post('hasEditable'))
{
$model = $this->findModel($model['flagging_id']);
$out = Json::encode(['output'=>'', 'message'=>'']);
$post = [];
$posted = current($_POST['Flagging']);
$post['Flagging'] = $posted;
if ($model->load($post)) {
$model->save();
$output = '';
if (isset($posted['sdv_status']))
{
$output = $model->sdv_status;
}
$out = Json::encode(['output'=>$output, 'message'=>'']);
}
echo $out;
return;
}
return $this->render('monitoring',
[
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'Countries' => $Countries,
'model'=>$model,
'allocatedsites' => $allocatedsites,
]);
}
The problem is I can't update my model because of I can't get the id.
I just need the id to update specific row.How can I get the id while using editable column?
Thanks in advance.

Actually the solution is easy. I just need the id of that specific row to update that.And in my ajax post I got something like this:
Flagging[0][status] NO
_csrf TlhyUm5kajAoNxgVNy0/ZCoyHApZUlNUFh0rB1gRPGoAFSIdGSAifQ==
editableIndex 0
editableKey 13
hasEditable 1
and found the editableKey is the id of that specific row!
Now in my controller I write down this code given below:
$_id=$_POST['editableKey'];
$model = $this->findModel($_id);
Here $_id is the posted editableKey value which is the id of the specific row.
and with the id I use it to get the specific model and just update data based on that id.

Related

Updating a document in laravel firestore

Hi I've been trying out things in updating aa document in firestore from laravel 9. But it doesn't seem to work at all.
What I have tried so far:
$product = app('firebase.firestore')
->database()
->collection('Products')
->document('15da5077cf8940f797db')
->update([
'path' => 'status',
'value' => 'archive'
]);
and
$status = "archive";
$currentData = json_decode(json_encode([
'status' => $status,
]));
$newData = [
'status' => $status,
];
$postData = app('firebase.firestore')
->database()
->collection('Products')
->document('15da5077cf8940f797db');
$postData->update([[
'path' => 'Products',
'value' => FieldValue::arrayRemove([$currentData])
]]);
$postData->set([
'Products' => FieldValue::arrayUnion($newData)
], ['merge' => true]);
and, javascript
const app = initizalizeApp(firebaseConfig);
const db = getFirestore(app);
btnArchive.addEventListener('click', (e) =>{
archiveDoc(doc(db, "Products", "15da5077cf8940f797db"), {
status: archive,
})
alert('Product archived!')
});
I want to update the status of a product from active to archive. But this doesn't work at all. Also is there another way to edit a document without specifying it?
this is how my collection looks like, each document has its own product details:

Map array values to collection of items

How would one do the following elegantly with laravel collections ?
Map the values of the $baseMap as keys to the collection.
The baseMap :
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
The collection :
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
//...
]);
The end result :
$result =[
[
'new_name' => 'name1',
'new_year' => '1000',
],
[
'new_name'=> 'name2',
'new_year' => '2000',
],
];
I know how to do it in plain php , just wondering what a nice collection version would be. Thanks!
I tried to find collection methods, or php functions, but without success. Some dirty code that works with different keys from both sides (items and basemap).
$result = $items->map(function($item) use ($baseMap) {
$array = [];
foreach($baseMap as $oldKey => $newKey){
if(isset($item[$oldKey])){
$array[$newKey] = $item[$oldKey];
}
}
return $array;
});
$result = $result->toArray();
Thanks to #vivek_23 and #IndianCoding for giving me idea's I ended up with the following :
I made a small edit to make sure the mapping and the items keys lined up.
so you don't have to worry of misalignment and all in laravel collection !
$baseMap = collect($baseMap)->sortKeys();
$result = $items->map(function ($item) use ($baseMap) {
return $baseMap->values()
->combine(
collect($item)->sortKeys()->intersectByKeys($baseMap)
)
->all();
});
Use intersectByKeys to filter your baseMap keys with $items values.
$result = $items->map(function($item,$key) use ($baseMap){
return array_combine(array_values($baseMap),collect($item)->intersectByKeys($baseMap)->all());
});
dd($result);
Update:
In a pure collection way,
$baseMapCollect = collect($baseMap);
$result = $items->map(function($item,$key) use ($baseMapCollect){
return $baseMapCollect->values()->combine(collect($item)->intersectByKeys($baseMapCollect->all())->values())->all();
});
dd($result);
Here are my two cents, using map. Don't know how dynamic your collection should be, but knowing the keys I would do the following:
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
])->map(function($item, $key) use ($baseMap) {
return [
$baseMap['name'] => $item['name'],
$baseMap['year'] => $item['year']
];
});

Update fields in a pivot table Laravel 5.5

I have 3 tables (2 + pivot) :
categories
id
admin_id
created_at
updated_at
deleted_at
langs
id
langname_fr
langname
....
lang_sector
lang_id
sector_id
sectname
sectshortname
....
I created a form which allow to create several entries depending the number of languages i defined ...
{!! Form::open( array('route' => 'maps.store','method' => 'POST') ) !!}
<fieldset>
<legend>Nom du secteur</legend>
#foreach($langs as $lang)
<div class="form-group m-form__group">
{{ Form::label( 'Nom du secteur en ' . $lang->langname_fr) }}
{{ Form::text('sectname_lang_' . $lang->id, '' , [ 'class' => 'form-control m-input' ]) }}
</div>
<div class="form-group m-form__group">
{{ Form::label( 'Nom abrégé du secteur en ' . $lang->langname_fr ) }}
{{ Form::text('sectshortname_lang_' . $lang->id, '', [ 'class' => 'form-control m-input' ]) }}
</div>
#endforeach
</fieldset>
...
{!! Form::close() !!}
If i want to create an entry in my database, i have to create several entries ...
public function sectorCreate(Request $request) {
Sector::create(array(
'admin_id' => Auth::guard('admin')->user()->id,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
));
$sector = Sector::all()->last();
$sector_id = Sector::all()->last()->id;
$countLang = Lang::count();
for ($i = 1; $i <= $countLang; $i++) {
$insertSector[$i] = $sector->langs()->attach(
$sector_id,
[
'lang_id' => $i,
'sectname' => $request->input('sectname_lang_' .$i),
'sectname_slug' => Str::slug($request->input('sectname_lang_' .$i)),
'sectshortname' => $request->input('sectshortname_lang_' .$i),
'sectdescription' => $request->input('sectdescription_lang_' .$i),
'sectshortdescription' => $request->input('sectshortdescription_lang_' .$i),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
'deleted_at' => NULL
]
);
}
return redirect()->route('admin.home')->with('success', 'Secteur créé');
}
Now my issue is to know how i can update the values of the database and to delete the entry ... I tried to read the documentation but i'm not sure i understood it.
For example
lang_id sector_id sectname sectshortname
-------------------------------------------------------
1 1 longname1 shortname1
2 1 longname2 shortname2
After update i would like to update sectname and sectshortname ... I have made several trials using sync, syncWithoutDetaching and updateExistingPivot without success...
I also add constraints by considering lang_id and sector_id as a primary key ...
UPDATE ----------------------------------------------------------
I modified the update method using sync and syncWithoutDetaching
public function update(Request $request, $id)
{
$sector = Sector::findOrFail($id);
$countLang = Lang::count();
$langs = Lang::all();
foreach ($langs as $lang) {
$lang_id = $lang->id;
}
for ($i = 1; $i <= $countLang; $i++) {
$insertSector[$i] = $sector->langs()->sync(
$sector->id,
$lang_id,
[
'sectname' => $request->input('sectname_lang_' .$i),
'sectname_slug' => Str::slug($request->input('sectname_lang_' .$i)),
'sectshortname' => $request->input('sectshortname_lang_' .$i),
'sectdescription' => $request->input('sectdescription_lang_' .$i),
'sectshortdescription' => $request->input('sectshortdescription_lang_' .$i),
'updated_at' => Carbon::now(),
'deleted_at' => NULL
]
);
}
return $insertSector;
//return redirect()->route('maps.index')->with('success', 'updated');
}
The Documentation states the following:
When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table:
$user->roles()->attach($roleId, ['expires' => $expires]);
You got this part correct. Now for updating (and or deleting):
Deleting
$user->roles()->detach([1, 2, 3]);
This removes associated records and clears the intermediate table.
Syncing Associations
You may also use the sync method to construct many-to-many associations. The sync method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given array will exist in the intermediate table:
$user->roles()->sync([1, 2, 3]);
You may also pass additional intermediate table values with the IDs:
$user->roles()->sync([1 => ['expires' => true], 2, 3]);
If you do not want to detach existing IDs, you may use the syncWithoutDetaching method:
$user->roles()->syncWithoutDetaching([1, 2, 3]);
Conclusion
Use sync, and set the attributes again. If you just want to update a few records, use the syncWithoutDetaching.
Update
Change your update code to this:
$insertSector[$i] = $sector->langs()->sync(
$lang_id =>
[
'sectname' => $request->input('sectname_lang_' .$i),
'sectname_slug' => Str::slug($request->input('sectname_lang_' .$i)),
'sectshortname' => $request->input('sectshortname_lang_' .$i),
'sectdescription' => $request->input('sectdescription_lang_' .$i),
'sectshortdescription' => $request->input('sectshortdescription_lang_' .$i),
'updated_at' => Carbon::now(),
'deleted_at' => NULL
]
);
You passed both the sector->id and the $lang_id where you only needed to pass the $lang_id with attributes for the intermediate table.
Finally thanks to Douwe de Haan i finally solved my issue for creating an entry with pivot table ... i guess i understood a little bit how it work now
Here is the method :
public function store(Request $request)
{
Sector::create(array(
'admin_id' => Auth::guard('admin')->user()->id,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
));
$sector = Sector::all()->last();
$countLang = Lang::count();
$langs = Lang::all();
foreach ($langs as $lang) {
$lang_id[] = $lang->id;
}
for ($i=0 ; $i < $countLang; $i++) {
$insertSector[$i] = $sector->langs()->syncWithoutDetaching(
[$lang_id[$i] =>
[
'sectname' => $request->input('sectname_lang_' .$lang_id[$i]),
'sectname_slug' => Str::slug($request->input('sectname_lang_' .$lang_id[$i])),
'sectshortname' => $request->input('sectshortname_lang_' .$lang_id[$i]),
'sectdescription' => $request->input('sectdescription_lang_' .$lang_id[$i]),
'sectshortdescription' => $request->input('sectshortdescription_lang_' .$lang_id[$i]),
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
'deleted_at' => NULL
]
]
);
}
return redirect()->route('maps.index')->with('success', 'Secteur créé');
}
For updating :
public function update(Request $request, $id)
{
$sector = Sector::findOrFail($id);
$countLang = Lang::count();
$langs = Lang::all();
foreach ($langs as $lang) {
$lang_id[] = $lang->id;
}
for ($i=0 ; $i < $countLang; $i++) {
$insertSector[$i] = $sector->langs()->updateExistingPivot(
$lang_id[$i],
[
'sector_id' => $request->input('sector_id'),
'sectname' => $request->input('sectname_lang_' .$lang_id[$i]),
'sectname_slug' => Str::slug($request->input('sectname_lang_' .$lang_id[$i])),
'sectshortname' => $request->input('sectshortname_lang_' .$lang_id[$i]),
'sectdescription' => $request->input('sectdescription_lang_' .$lang_id[$i]),
'sectshortdescription' => $request->input('sectshortdescription_lang_' .$lang_id[$i]),
'updated_at' => Carbon::now(),
'deleted_at' => NULL
]
);
}
return $insertSector;
//return redirect()->route('sectors.index')->with('success', 'Secteur mis à jour');
}

Codeigniter update_batch--view, but not execute

I am using Codeigniter 3.x and want to see an update_batch query, but not run it, while I am debugging the code.
This works for an update_batch:
$this->db->update_batch("`" . $this->fullGamesTable . "`", $fullGames, 'gameid');
and updates the database, but I want to view the update and not actually do the update.
Thanks.
Can you do like this
$data = array(
array(
'opt_id' => $hoptid1,
'q_id' => $hid,
'opt_val' => $sin_yes,
'opt_crct' => $sin_yescrt,
'opt_mark' => '1'
),
array(
'opt_id' => $hoptid2,
'q_id' => $hid,
'opt_val' => $sin_no,
'opt_crct' => $sin_nocrt,
'opt_mark' => '1'
)
);
$this->db->update_batch('option', $data, 'opt_id');
Try this
public function update_batch()
{
$data = $this->db->select('id,description')->from('insert_batch')->group_by('url')->get()->result_array();
$batch_update = [];
foreach ($data as $key => $value) {
$value['description'] = 'description';
$batch_update[] = [
'id' =>$value['id'],
'description' => $value['description']
];
}
echo "<pre>"; print_r($batch_update);
$this->db->update_batch('insert_batch',$batch_update,'id');
}

Yii2: Reusing Form Fields through Widget

I have a field that is a Select2 widget field and it's usually used in many forms, but copy pasting the same code after a while gets really annoying. Therefore I decided perhaps its best to create a widget just for this field.
The field is as follows
<?= $form->field($model, 'contact_id')->widget(Select2::className(), [
'initValueText' => empty($model->contact_id) ? '' : $model->contact->contact_id . ' ' . $model->contact->fullname,
'options' => [
'class' => 'input-sm',
'id' => 'contact_id',
'placeholder' => '-- Search --',
'disabled' => $disabled,
'onchange' => new JsExpression("get_contact_info($(this).val())"),
],
'pluginOptions' => [
'allowClear' => true,
'language' => [
'errorLoading' => new JsExpression("function () { return 'Waiting for results...'; }"),
],
'ajax' => [
'url' => $fetch_url,
'dataType' => 'json',
'data' => new JsExpression('function(params) { return {q:params.term}; }'),
'results' => new JsExpression('function(data,page) { return {results:data.results.text}; }'),
],
'escapeMarkup' => new JsExpression('function (markup) { return markup; }'),
'templateResult' => new JsExpression('function(contact) { return contact.text; }'),
'templateSelection' => new JsExpression('function (contact) { return contact.text; }'),
],
]); ?>
This field utilizes Ajax Fetching, and must allow to be used in create and update forms.
Can anyone please point me to the right direction.
I see two solution:
a) create widget - more work, but flexible using by adding additional settings
b) create separate view and render it - faster, but no so flexible

Resources