I have an editable GridView in my Yii2 app and using kartik EditableColumn. When there was only one editable column everything works Ok but when I tried to add one more editable column it saves editted value of Price column and sets to zero the value of expire_days column. The same for opposite way(if update expire_days it saves the value but sets to zero the Price value).
The View:
'columns' => [
[
'class'=>'kartik\grid\EditableColumn',
'attribute' => 'price',
'editableOptions'=>[
'header'=>' ',
'inputType'=>\kartik\editable\Editable::INPUT_SPIN,
'options'=>['pluginOptions'=>['min'=>0, 'max'=>5000000]]
],
'value' => function ($model) {
return $model->price;
},
'filter' => Category::getPrices(),
'format' => 'raw'
],
[
'class'=>'kartik\grid\EditableColumn',
'attribute' => 'expire_days',
'editableOptions'=>[
'header'=>' ',
'inputType'=>\kartik\editable\Editable::INPUT_SPIN,
'options'=>['pluginOptions'=>['min'=>0, 'max'=>100]]
],
'value' => function ($model) {
return $model->expire_days;
},
'filter' => Category::getExpDays(),
'format' => 'raw'
],
]
Controller:
if (Yii::$app->request->post('hasEditable')) {
$model = new Category();
$id = Yii::$app->request->post('editableKey');
$model = Category::findOne($id);
$out = Json::encode(['output'=>'', 'message'=>'']);
$post = [];
$posted = current($_POST['Category']);
$post['Category'] = $posted;
if ($model->load($post)) {
$model->price = $post['Category']['price'];
$model->expire_days = $post['Category']['expire_days'];
$model->save();
$output = '';
$out = Json::encode(['output'=>$output,'message'=>'']);
}
echo $out;
return;
}
You should separately process two scenarios:
if ($model->load($post)) {
if ($post['Category'] && $post['Category']['price']) {
$model->price = $post['Category']['price'];
}
if ($post['Category'] && $post['Category']['expire_days']) {
$model->expire_days = $post['Category']['expire_days'];
}
$model->save();
$output = '';
$out = Json::encode(['output'=>$output,'message'=>'']);
}
If you receive price - you update only price. If you receive expire_days - update expire_days.
Related
I know there is a very simple solution requiring minor adjustment to my code but I'm stuck and I have wasted a lot of time trying to find the solution.
Using Laravel Excel I am able to export successfully except that the row numbers are off.
I was able to deduce that the numbering begins with the total number rows within the collection, but they are supposed to begin at 1.
Any help is greatly appreciated.
protected $table_data;
private $row = 0;
public function __construct(array $table_data)
{
$this->table_data = $table_data;
}
public function model(array $row)
{
++$this->row;
}
public function columnFormats(): array
{
return [
'E' => '0',
];
}
public function map($table_data): array
{
$department = (empty($table_data['department'])) ? 'Cast' : $table_data['department']['name'];
return [
++$this->row,
$department,
$table_data['name'],
$table_data['name_eng'],
$table_data['phone_number'],
$table_data['email'],
];
}
public function startCell(): string
{
return 'A6';
}
public function drawings()
{
$drawing = new Drawing();
$drawing->setName('Logo');
$drawing->setPath(public_path('/images/form_logo.png'));
$drawing->setHeight(90);
$drawing->setCoordinates('A1');
return $drawing;
}
public function headings(): array
{
return [
[
'#',
'Department',
'Position/Role',
'Name',
'Phone',
'Email',
]
];
}
public function styles(Worksheet $sheet)
{
$sheet->getStyle('A6:F6')->getFill()->applyFromArray(['fillType' => 'solid','rotation' => 0, 'color' => ['rgb' => '7BC1FA'],]);
$styleArray = array(
'font' => array(
'bold' => true,
'color' => array('rgb' => 'FFFFFF'),
'size' => 12,
'name' => 'Arial'
));
$sheet->getStyle('A6:F6')->applyFromArray($styleArray)->getAlignment()->setWrapText(true)->setHorizontal('left');
}
public function array(): array
{
return $this->table_data;
}
The problem is probably ++$this->row being executed at least twice as often as you expect. I'm not sure if that's because you have it both in model and map method but it might as well go wrong if it's only in map or you are not using import features and it's in model.
So I'd suggest a different solution:
If you are only exporting Data and specifically using the array approach for your data you could add the row index on the data set and use it in map and so on:
public function __construct(array $table_data)
{
$newTableData = [];
foreach($table_data as $index => $data) {
// add row index
$newTableData[] = array_merge(['row' => $index], $data);
}
$this->table_data = $newTableData;
}
//...
public function map($table_data): array
{
$department = (empty($table_data['department'])) ? 'Cast' : $table_data['department']['name'];
return [
// use row index
$table_data['row'],
$department,
$table_data['name'],
$table_data['name_eng'],
$table_data['phone_number'],
$table_data['email'],
];
}
I make a parser of items from DotA 2 user inventory in the Steam service. Every time I try to parse user data, I get an empty value:
{"success":true,"items":[]}, but there are items in my Steam inventory.
My function to parse items:
public function loadMyInventory() {
if(Auth::guest()) return ['success' => false];
$prices = json_decode(Storage::get('prices.txt'), true);
$response = json_decode(file_get_contents('https://steamcommunity.com/inventory/'.$this->user->steamid64.'/570/2?l=russian&count=5000'), true);
if(time() < (Session::get('InvUPD') + 5)) {
return [
'success' => false,
'msg' => 'Error, repeat in '.(Session::get('InvUPD') - time() + 5).' сек.',
'status' => 'error'
];
}
//return $response;
$inventory = [];
foreach($response['assets'] as $item) {
$find = 0;
foreach($response['descriptions'] as $descriptions) {
if($find == 0) {
if(($descriptions['classid'] == $item['classid']) && ($descriptions['instanceid'] == $item['instanceid'])) {
$find++;
# If we find the price of an item, then move on.
if(isset($prices[$descriptions['market_hash_name']])) {
# Search data
$price = $prices[$descriptions['market_hash_name']]*$this->config->curs;
$class = false;
$text = false;
if($price <= $this->config->min_dep_sum) {
$price = 0;
$text = 'Cheap';
$class = 'minPrice';
}
if(($descriptions['tradable'] == 0) || ($descriptions['marketable'] == 0)) {
$price = 0;
$class = 'minPrice';
$text = 'Not tradable';
}
# Adding to Array
$inventory[] = [
'name' => $descriptions['market_name'],
'price' => floor($price),
'color' => $this->getRarity($descriptions['tags']),
'tradable' => $descriptions['tradable'],
'class' => $class,
'text' => $text,
'classid' => $item['classid'],
'assetid' => $item['assetid'],
'instanceid' => $item['instanceid']
];
}
}
}
}
}
Session::put('InvUPD', (time() + 5));
return [
'success' => true,
'items' => $inventory
];
}
But should return approximately the following value:
{"success":true,"items":[{"classid":"2274725521","instanceid":"57949762","assetid":"18235196074","market_hash_name":"Full-Bore Bonanza","price":26}]}
Where my mistake?
First of all, you are iterating on descriptions for every assets, which is assets*descriptions iteration, it's quite a lot, but you can optimize this.
let's loop once for descriptions and assign classid and instanceid as object key.
$assets = $response["assets"];
$descriptions = $response["descriptions"];
$newDescriptions=[];
foreach($descriptions as $d){
$newDescriptions[$d["classid"]][$d["instanceid"]] = $d;
}
this will give as the ability to not loop over description each time, we can access the description of certain asset directly $newDescriptions[$classid][$instanceid]]
foreach($assets as $a){
if(isset($newDescriptions[$a["classid"]]) && isset($newDescriptions[$a["classid"]][$a["instanceid"]])){
$assetDescription = $newDescriptions[$a["classid"]][$a["instanceid"]];
$inventory = [];
if(isset($prices[$assetDescription["market_hash_name"]])){
$price = $prices[$assetDescription['market_hash_name']]["price"]*$this->config->curs;
$class = false;
$text = false;
if($price <= $this->config->min_dep_sum) {
$price = 0;
$text = 'Cheap';
$class = 'minPrice';
}
if(($assetDescription['tradable'] == 0) || ($assetDescription['marketable'] == 0)) {
$price = 0;
$class = 'minPrice';
$text = 'Not tradable';
}
$inventory["priceFound"][] = [
'name' => $assetDescription['market_name'],
'price' => floor($price),
'color' => $this->getRarity($assetDescription['tags']),
'tradable' => $assetDescription['tradable'],
'class' => $class,
'text' => $text,
'classid' => $a['classid'],
'assetid' => $a['assetid'],
'instanceid' => $a['instanceid']
];
}else{
$inventory["priceNotFound"][] = $assetDescription["market_hash_name"];
}
}
}
About your mistake:
are you Sure your "prices.txt" contains market_hash_name?
I don't see any other issue yet, operationg on the data you have provided in comment, I got print of variable $assetDescription. Please doublecheck variable $prices.
Here am trying Dependent dropdown using kartik depdrop yii2 extension . the process of this dependent dropdown is, if i select a productname it will show me the dependent batchno, then if select a batchno, it will show the dependent itemid.
Actually first level is working perfectly, if i select a productname, it will show me batchno, this action is working perfectly, but the problem on the second level. if i select a batchno it need to show me a itemid, this action is not working
And am getting error as this image -
Controller
public function actionSubcat() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$cat_id = $parents[0];
$out = Productbatch::getBatchNo($cat_id);
echo Json::encode($out);
// the getSubCatList function will query the database based on the
// cat_id and return an array like below:
// [
// ['id'=>'<sub-cat-id-1>', 'name'=>'<sub-cat-name1>'],
// ['id'=>'<sub-cat_id_2>', 'name'=>'<sub-cat-name2>']
// ]
//echo Json::encode(['output'=>$out, 'selected'=>'']);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
public function actionProd() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$ids = $_POST['depdrop_parents'];
$cat_id = empty($ids[0]) ? null : $ids[0];
$subcat_id = empty($ids[1]) ? null : $ids[1];
if ($cat_id != null) {
$data = Productbatch::getItemid($cat_id, $subcat_id);
/**
* the getProdList function will query the database based on the
* cat_id and sub_cat_id and return an array like below:
* [
* 'out'=>[
* ['id'=>'<prod-id-1>', 'name'=>'<prod-name1>'],
* ['id'=>'<prod_id_2>', 'name'=>'<prod-name2>']
* ],
* 'selected'=>'<prod-id-1>'
* ]
*/
echo Json::encode($out);
//echo Json::encode(['output'=>$out, 'selected'=>$data['selected']]);
return;
}
}
echo Json::encode(['output'=>'', 'selected'=>'']);
}
_form
<?= $form->field($model, 'productname')->widget(Select2::classname(), [
'data' => ArrayHelper::map(Productnames::find()->all(),'productnames_productname','productnames_productname'),
'language' => 'en',
'options' => ['placeholder' => 'Select Product Name', 'id' => 'cat-id'],
'pluginOptions' => [
'allowClear' => true
],
]); ?>
<?= $form->field($model, 'batchno')->widget(DepDrop::classname(), [
'options'=>['id'=>'subcat-id'],
'pluginOptions'=>[
'depends'=>['cat-id'],
'placeholder'=>'Select BatchNo',
'url'=>Url::to(['/production/productbatch/subcat'])
]
]); ?>
<?= $form->field($model, 'itemid')->widget(DepDrop::classname(), [
'pluginOptions'=>[
'depends'=>['cat-id', 'subcat-id'],
'placeholder'=>'Select ItemId',
'url'=>Url::to(['/production/productbatch/prod'])
]
]); ?>
Model
public static function getBatchNo($cat_id)
{
$out = [];
$data = Productbatch::find()
->where(['productname' => $cat_id])
->asArray()
->all();
foreach ($data as $dat) {
$out[] = ['id' => $dat['itemid'], 'name' => $dat['batchno']];
}
return $output = [
'output' => $out,
'selected' => ''
];
}
public static function getItemid($cat_id, $subcat_id)
{
$out = [];
$data = Productbatch::find()
->where(['productname' => $cat_id])
->andWhere(['batchno' => $subcat_id])
->asArray()
->all();
$selected = '';
foreach ($data as $dat => $datas) {
$out[] = ['id' => $datas['itemid'], 'name' => $datas['itemid']];
if($dat == 0){
$aux = $datas['itemid'];
}
($datas['productname'] == $cat_id) ? $selected = $cat_id : $selected = $aux;
}
return $output = [
'output' => $out,
'selected' => $selected
];
}
You need do like this in your controller. You have to create new action in controller .
public function actionState() {
$country_id = $_POST['depdrop_parents'][0];
$state = State::find()->where(['country_id' => $country_id])->all();
$all_state = array();
$i = 0;
foreach ($state as $value) {
$all_state[$i]['id'] = $value['state_id'];
$all_state[$i]['name'] = $value['state_name'];
$i++;
}
echo Json::encode(['output' => $all_state, 'selected' => '']);
return;
}
i also suffered from this problem but finally I solved this issue..
I am new to WordPress. I am trying to create a WordPress table using WP_List_Table class. I created a table but it takes a long time. So, I want to create a function that allows me to create a WordPress table, where I can pass data and column array to the function and that function will, then, create the required WordPress table. I want to create table with edit, delete and sort-able functionality.
hey try this code it dynamic function but you need to pass first argument kay and name is id.
this is my class that is dynamic create the WP_List_table.
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of wplist_table
*
* #author renishkhunt
*/
if (!class_exists('WP_List_Table')) {
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}
class wplist_table extends WP_List_Table
{
//put your code here
var $data = array();
var $default_columns = array();
public function wplist_table($datad, $columns)
{
parent::__construct();
$this->data = $datad;
$this->default_columns = $columns;
}
function get_columns()
{
return $this->default_columns;
}
function prepare_items()
{
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
usort($this->data, array(&$this, 'usort_recorder'));
$per_page = 10;
$current_page = $this->get_pagenum();
$total_items = count($this->data);
// only ncessary because we have sample data
$this->found_data = array_slice($this->data, (($current_page - 1) * $per_page), $per_page);
$this->set_pagination_args(array(
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page //WE have to determine how many items to show on a page
));
$this->items = $this->found_data;
}
function column_default($item, $column_name)
{
foreach ($this->default_columns as $keys => $values) {
if ($values == $column_name) {
if(isset($item[$column_name])){
return $item[$column_name];
}
}
}
}
function get_sortable_columns()
{
$i=0;
$sortables = array();
foreach ($this->default_columns as $keys => $values) {
if($i == 0){
$i++;
//continue;
}
$sortables[$keys] = array($values,false);
}
return $sortables;
}
function usort_recorder($a, $b)
{
$orderby = (!empty($_GET['orderby'])) ? $_GET['orderby'] : 'id';
$order = (!empty($_GET['order'])) ? $_GET['order'] : 'asc';
$resutl = strcmp($a[$orderby], $b[$orderby]);
return ( $order === 'asc') ? $resutl : -$resutl;
}
function column_Name($item)
{
$action = array(
'edit' => sprintf('Edit', $_REQUEST['page'], 'edit', $item['id']),
'delete' => sprintf('Delete', $_REQUEST['page'], 'delete', $item['id'])
);
return sprintf('%1$s %2$s', $item['name'], $this->row_actions($action));
}
function get_bulk_action()
{
$actions = array(
'delete' => 'Delete '
);
return $actions;
}
function column_db($item)
{
return sprintf("<input type='checkbox' name='id[]' value='%s'", $item['id']);
}
}
?>
just you copy that code in file and pass arguments like column name and data like this.
$data = array(
array("id" => 1, "name" => "Renish Khunt", "add" => "asd"),
array("id" => 2, "name" => "Renish Khunt", "add" => "asd"),
array("id" => 3, "name" => "Renish Khunt", "add" => "asd")
);
$columns = array(
"name" => "name",
"add" => "add"
);
then after create the class object and pass the two arguments the data and column name like this.
$mylist_table = new wplist_table($data, $columns);
echo '<div class="wrap"><h2>Custome Fields<a class="add-new-h2" href="?page=' . $_REQUEST['page'] . '&action=add">Add New</a></h2>';
$mylist_table->prepare_items();
$mylist_table->display();
echo "</div>";
i hope this is used full for you that is the dynamic class you need to display more column in $column array add column name and $data array add that name of column as key or value like this.
$data = array(
array("id" => 1, "name" => "Renish Khunt", "add" => "asd","newcolumn"=>"value"),
array("id" => 2, "name" => "Renish Khunt", "add" => "asd","newcolumn"=>"value"),
array("id" => 3, "name" => "Renish Khunt", "add" => "asd","newcolumn"=>"value")
);
$columns = array(
"name" => "name",
"add" => "add",
"newcolumn"=>"New Column"
);
like this i hope this code is used full for you.
thank you.
How to return the fetched data (in this case: $arr) back to my view
(which I can manipulate like displaying in a table).
If I have this in my controller action processed via ajax:
public function actionFetchregularload(){
$criteria = new CDbCriteria;
$criteria->limit = 15;
$criteria->condition='semester = 2';
$criteria->select = array('subjCode','subjDesc','lec','lab','units');
$criteria->addSearchCondition('yrLvl', $_GET['yrlevel']);
$data = CompeProspectusA::model()->findAll($criteria);
$arr = array();
foreach ($data as $item){
$arr[] = array(
'subjcode' => $item->subjCode,
'subjdesc' => $item->subjDesc,
'lab' => $item->lab,
'lec' => $item->lec,
'units' => $item->units,
);
}
}
Make a view with your table or something else and use renderPartial() in your actionFetchregularload() like this:
$this->renderPartial('_table', array('arr'=>$arr), false, true);
In your main view you can use CHtml::ajaxLink with options (where "#contentdiv" is id of your table div):
CHtml::ajaxLink(
"Update table",
Yii::app()->createUrl('controller/fetchregularload'),
array( //ajaxOptions
'type' => 'POST',
'beforeSend' => "function(request) {
$('#contentdiv').addClass('loading'); //add .loading class while loading - you can add background image
}",
'success' => "function(data) {
$('#contentdiv').removeClass('loading');
document.getElementById('contentdiv').innerHTML=data;
}",
),
//htmlOptions
array('href' => Yii::app()->createUrl('controller/fetchregularload'));
);