I have a problem with Yii2 (as usual). I'm trying to show many buttons in a cell in GridView. I have one ticket with four possible states:
1: OPEN
2: IN PROCESS
3: CLOSED
4: EDIT
In a column (ActionColumn?) I want to display many buttons to change it's state like this:
If the state is '1', I want to show two buttons: 'In process' and 'Close Ticket'.
If state is 2, I want to show only 'Close Ticket' button -> That's OK
If it's closed (state = 3), I want to show 'Edit Ticket' button -> That's OK
If state is 4, the I'll show 'Close Ticket' button -> That's OK
This is my code of that column in my GridView. I'm only able to show one button, don't know how to do it for showing more buttons, as you can't return more than one element, or an array:
[
'label' => 'Change State:',
'format' => 'raw',
'value' => function($dataProvider){
if($dataProvider->state== '1'){
return Html::a('In Process', ['/tickets/inprocessticket', 'id' => $dataProvider->id], ['class'=>'btn btn-warning', 'id' => 'btn_inProcessTicket']);
}else if($dataProvider->state== '2'){
return Html::a('Close Ticket', ['/tickets/closeticket', 'id' => $dataProvider->id], ['class'=>'btn btn-danger', 'id' => 'btn_closeTicket']);
}else if($dataProvider->state== '3'){
return Html::a('Edit Ticket', ['/tickets/editticket', 'id' => $dataProvider->id], ['class'=>'btn btn-info', 'id' => 'btn_editTicket']);
}else if($dataProvider->state== '4'){
return Html::a('Close Ticket', ['/tickets/closeticket', 'id' => $dataProvider->id], ['class'=>'btn btn-danger', 'id' => 'btn_closeTicket']);
}
},
],
Thank you all for your help!
If you want to use yii\grid\ActionColumn you should define the buttons in $buttons property and use $visibleButtons callbacks to determine which buttons should be displayed. You can use $template property to set their order.
[
'class' => \yii\grid\ActionColumn::class,
'template' => '{process} {edit} {close}' //here will be all posible buttons
'buttons' => [
'process' => function($url, $model, $key) {
return Html::a(
'In Process',
[
'/tickets/inprocessticket',
'id' => $model->id
],
[
'class'=>'btn btn-warning',
'id' => 'btn_inProcessTicket'
]
);
},
'edit' => function($url, $model, $key) {
return Html::a(
'Edit Ticket',
[
'/tickets/editticket',
'id' => $dataProvider->id
],
[
'class'=>'btn btn-info',
'id' => 'btn_editTicket'
]
);
},
'close' => function ($url, $model, $key) {
return Html::a(
'Close Ticket',
[
'/tickets/closeticket',
'id' => $dataProvider->id
],
[
'class'=>'btn btn-danger',
'id' => 'btn_closeTicket'
]
);
},
],
'visibleButtons' => [
'process' => function($model, $key, $index) {
//the in process button should only be shown if state == 1
return $model->state == 1;
},
'edit' => function($model, $key, $index) {
//the edit button should only be shown if state == 3
return $model->state == 3;
},
'close' => function($model, $key, $index) {
//the close button should be shown in each state except of state == 3
return $model->state != 3;
},
],
]
You can find more information about ActionColumn and it's callbacks in documentation.
Related
I am building a Widget for Elementor. It's a 'basic' widget where I need to grab the value of a control. Like, if I choose a select control a method will be called and will show another select control or something. Here is what I am doing:
protected function register_controls()
{
$this->start_controls_section(
'new_section',
[
'label' => esc_html__('Settings', 'textdomain'),
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
]
);
// New Select settings
$this->add_control(
'data_types',
[
'label' => esc_html__('Testimonial Type', 'textdomain'),
'type' => \Elementor\Controls_Manager::SELECT,
'options' => [
'static' => 'Static',
'dynamic' => 'Dynamic',
],
'default' => 'static',
]
);
// I want to get 'data_types' value here to call the *get_data_by_type($type)*
$this->end_controls_section();
}
public function get_data_by_type($type){
// Something will be done with the data type.
}
Maybe I'm in over my head but I'm trying to create an extension for WpGraphQL to just gather the YITH WooCommerce Product Add-Ons info for each product but I've gotten to the point of banging my head against the desk in frustration. Is there a fairly easy way to just output the array into nodes? The following is what I have so far, currently I'm only getting one product with a set ID (later, hopefully it will get the one associated with that query). I can get a simple string output but I can't get it to output the array into nodes? What am I doing wrong? I commented out ideas I had for an output but it just usually results in an error or null. I do see the graphql_debug working and outputting $fields as an array though? Thanks!
register_graphql_object_type('MyNewType', [
'description' => __('Describe the Type and what it represents', 'replace-me'),
'fields' => [
'nodes' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
'fields' => [
'form_type' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
],
],
],
],
]);
register_graphql_field(
'Product',
'YITH_fields',
[
'type' => 'MyNewType',
'description' => __('Example field added to the Post Type', 'replace-with-your-textdomain'),
'resolve' => function (\WPGraphQL\Model\Post $post) {
global $wpdb;
$sql = "SELECT wp_live_yith_wapo_types.type, wp_live_yith_wapo_types.options FROM wp_live_yith_wapo_groups JOIN wp_live_yith_wapo_types on wp_live_yith_wapo_groups.id = wp_live_yith_wapo_types.group_id WHERE FIND_IN_SET(13, products_id)";
$results = $wpdb->get_results($sql);
if ($results) {
$array = array('nodes');
//$array = array();
foreach ($results as $result) {
$type = array('form_type' => $result->type);
$options = maybe_unserialize($result->options);
$result = array_merge($type, $options);
$array[] = $result;
}
//$array = wp_json_encode($array);
$fields = !empty($array) ? $array : null;
} else {
$fields = null;
}
graphql_debug($fields, ['type' => 'ARGS_BREAKPOINT']);
//return $fields['nodes'];
return $fields;
}
]
);
Probably it's good enough to return an array of Info 'records' (without embedding into nodes subfield - it would require some, own 'InfoList' type def.), then you need a type for single Info, like:
register_graphql_object_type('MyInfoItem', [
'description' => __('Describe the Type and what it represents', 'replace-me'),
'fields' => [
'form_type' => [
'type' => 'String',
'description' => __('Describe what this field should be used for', 'replace-me'),
],
// options field - list of some scalar or custom type
'options' => [
'type' => [ 'list_of' => 'String' ],
'description' => __('Describe what this field should be used for', 'replace-me'),
],
],
]);
extend Product with:
register_graphql_field(
'Product',
'YITH_fields',
[
'type' => [ 'list_of' => 'MyInfoItem' ],
'description' => __('Example field added to the Post Type', 'replace-with-your-textdomain'),
'resolve' => function (\WPGraphQL\Model\Post $post) {
// ...
return [
['form_type' => 'some_value'],
[
'form_type' => 'other_value',
'options' => ['opt_1', 'opt_2'],
],
];
Any, not trivial data 'nesting level' requires a separate type definition.
For more complex options 'records' you need to register another type - e.g. ids required for optional option selection.
If you don't want to explicitely express these [unknown/dynamic] structures, you can use custom JSON scalar type.
Ok I read a lot about this one, mainly here : https://github.com/symfony/symfony/issues/19953
But I still can't get a simple solution;
I want to display a select with this data :
$data = [
2 => 'Label 1',
5 => 'Label 2',
6 => 'Label 1',
11 => 'Label 3',
]
I use optgroup, so I can have several identical labels (Label 1 here).
But how can I show them in my ChoiceType ? For now I have:
$builder
->add('type', ChoiceType::class, [
'label' => 'Type',
'required' => true,
'choices' => $options['data'],
'choice_label' => function ($value) {
return $value;
},
'choice_value' => function ($value) {
// how to get correct value here ?
},
])
This example show my select list with duplicatas, but values are like 0, 1, 2, 3 .....
And if I remove choice_label, it doesn't show duplicata.
I tried this :
# app/config.yml
framework:
form:
choices_as_values: false # defaults to true
But the option seems to not exist on Symfony 3.4. Any clue ?
Your problem appears to be happening when you have IDs as values from possibly entities. If they are indeed entities, please use the EntityType!!!
... that being said ...
okay, what symfony essentially does is have its choices array in the form [ label => value ], which obviously is a problem when handling duplicate labels.
I believe the simplest way around this should be:
$new = [
(object) ['value' => 2, 'label' => 'Label 1'],
(object) ['value' => 5, 'label' => 'Label 2'],
(object) ['value' => 6, 'label' => 'Label 1'],
(object) ['value' => 11, 'label' => 'Label 3'],
];
which could be generated fairly quickly via
$new = [];
foreach($old_choices as $value => $label) {
$new[] = (object) ['value' => $value, 'label' => $label];
}
then you can set
'choices' => $new,
'choice_label' => function($entry) { return $entry->label; },
'choice_value' => function($entry) { return $entry->value; },
(or the property path)
I'm not quite certain what would be returned in the final $form->getData(), but I hope it's the value.
If you still want to group the values, the group_by option should work.
I want to display a list of items by ajax on a link click. My link html is
<a class="get-list use-ajax ajax-processed" href="get-my-list">My List</a>
I can do this in Drupal 7 by:
return array(
'#type' => 'ajax',
'#commands' => array(
ajax_command_append('#my-wrapper', theme('item_list', array('items' => $my_list, 'attributes' => array('class' => array('my-list'))))),
),
);
How to return an ajax callback like this in Drupal 8?
You may want to have a look at the drupal 8 Ajax API (https://api.drupal.org/api/drupal/core!core.api.php/group/ajax/8)
You can define your own callback function or if you have a link you can go to the method of the controller. Here you will have to define an AjaxResponse and put commands in the response.
Here's an example from my project.
The link buildup
$build['ajax-link'] = [
'#title' => '',
'#type' => 'link',
'#id' => 'ajax-link',
'#url' => $url,
'#ajax' => [
'event' => 'click',
'progress' => [
'type' => 'none',
],
],
'#attributes' => [
'class' => [
'fa fa-heart-o fa-2x ' . $activeClass,
],
'title' => 'Ajax heart',
],
];
The controller method it calls
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand('#ajax-link', $this->subscribeElementGenerator->generateSubscribeElement($event)));
return $response;
The ReplaceCommand just re-generates the link to update it.
I'm working with Yii 2, and it's grid view to show information.
Now, my problem is that whenever a user scans two identical serial numbers and/or mac addresses, it should highlight the row (change color to red), and show some error sign or whatever.
Screenshot:
What I want it to look like:
I'm new to Yii2 and don't exactly know how they do it with the grid view. I've been researching on this specific problem but couldn't find anything.
Code for Gridview
<?= GridView::widget([
'id' => 'scan-batch-grid',
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
['class' => 'yii\grid\CheckboxColumn'],
[
'attribute' => 'product_ID',
'value' => 'product.name'
],
'SN',
'MAC',
[
'class' => 'yii\grid\ActionColumn',
'urlCreator' => function ($action, $model, $key, $index) {
return Url::to(['scan-batch/view', 'id' => $key, 'scan' => $model->scan_batch_ID]);
},
'buttons' => [
'update' => function ($url, $model, $key) {
return '';
},
'delete' => function ($url, $model, $key) {
return '';
},
],
],
],
]); ?>
EDIT
I only want to know how to change the color of only one row.
Got it!
Yii2 : Adding Classes to Rows in the GridView (YouTube)
Yii2 Gridview row by row css expression
Simply add rowOptions to your gridview.
<?= GridView::widget([
'id' => 'scan-batch-grid',
'dataProvider' => $dataProvider,
'rowOptions'=>function($model){
if($a == $b){
return ['class' => 'danger'];
}
},
Thanks for posting your answer Paramone. Worked great.
Here is my implementation:
<?= GridView::widget([
'dataProvider' => $dataProvider,
'rowOptions' => function ($model) {
if ($model->name == 'test') {
return ['class' => 'info'];
}
},