Select2 Filter Error - search

I have a filter gridview like this
This tag filter is working fine, but whe i go to the page 2, this tag can not be deleted.
VIEW
[
'attribute' => 'color',
'value' => function ($model) {
return $model->color->name;
},
'filterType'=>GridView::FILTER_SELECT2,
'filter'=>ArrayHelper::map(\app\models\Color::find()->asArray()->all(), 'name', 'name'),
'filterWidgetOptions'=>[
'pluginOptions'=>['allowClear'=>true, 'minimuminputLength' => 3],
],
'filterInputOptions'=>['placeholder'=>'Any Color', 'multiple' => true ],
'group'=>true, // enable grouping
'label' => 'Code',
'headerOptions' =>
['style'=>'max-width: 70%; font-size: 12px;overflow: auto; word-wrap: break-word;'],
'contentOptions' =>
['style'=>'max-width: 70%; font-size: 12px;overflow: auto; word-wrap: break-word;'],
],
'amount',

Related

ag grid does not react to scroll in infinite scrolling pagination

I have server side pagination. I've created a simple back-end service to mimic it. See https://gitlab.com/sunnyatticsoftware/sasw-community/sasw-pagination-tester
The back-end can be run as a docker container on port 5000 (or any other) with
docker run -p 5000:8080 registry.gitlab.com/sunnyatticsoftware/sasw-community/sasw-pagination-tester:latest
This is gonna allow to query items (i.e: tickets in this case) with pagination filtering. See its swagger http://localhost:5000/swagger for more info and/or to interact with the sample.
It works in a pretty standard way.
To retrieve the first page with pagination size of 5 items per page:
GET http://localhost:5000/api/tickets?Page=1&Count=5
To retrieve the second page with pagination size of 5 items per page:
GET http://localhost:5000/api/tickets?Page=2&Count=10
etcetera.
The result would have enough information to be able to draw any table on a UI with pagination links and info about total items and total pages:
{
"items": [
{
"id": "00000001-0000-0000-0000-000000000000",
"channel": "chat",
"subject": "one"
},
{
"id": "00000002-0000-0000-0000-000000000000",
"channel": "email",
"subject": "two"
},
{
"id": "00000003-0000-0000-0000-000000000000",
"channel": "email",
"subject": "three"
},
{
"id": "00000004-0000-0000-0000-000000000000",
"channel": "phone",
"subject": "four"
},
{
"id": "00000005-0000-0000-0000-000000000000",
"channel": "chat",
"subject": "five"
}
],
"pageNumber": 1,
"pageSize": 5,
"totalPages": 7,
"totalCount": 32
}
THE PROBLEM
I want to use agGrid for the UI, with infinite scrolling, but I am struggling with the examples, as they all seem to have a previous fetch of a json that later is sliced to show results while scrolling. It would've been useful to have a sample with real integration, but in theory that shouldn't be a problem.
I cannot have the infinite scroll working. For whatever reason, it loads the first items but then the agGrid does not trigger the getRows anymore, and I don't know what am I missing.
I would like to have a simple infinite scrolling example working with the server-side pagination already in place. The following html/js won't send a second request to the server after scrolling.
The index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript example</title>
<meta charSet="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style media="only screen">
html, body {
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
html {
position: absolute;
top: 0;
left: 0;
padding: 0;
overflow: auto;
}
body {
padding: 1rem;
overflow: auto;
}
</style>
</head>
<body>
<div id="myGrid" style="height: 100%" class="ag-theme-alpine-dark">
</div>
<script>var __basePath = './';</script>
<script src="https://unpkg.com/ag-grid-enterprise#28.1.3/dist/ag-grid-enterprise.min.js">
</script>
<script src="main.js">
</script>
</body>
</html>
and the main.js
(() => {
const gridOptions = {
columnDefs: [
{ valueGetter: 'node.rowIndex', maxWidth: 100 },
{ field: 'id', minWidth: 150 },
{ field: 'channel', minWidth: 150 },
{ field: 'subject', minWidth: 400 }
],
defaultColDef: {
flex: 1,
minWidth: 80,
},
rowModelType: 'serverSide',
serverSideInfiniteScroll: true,
cacheBlockSize: 10,
maxBlocksInCache: 2,
rowBuffer: 0,
//blockLoadDebounceMillis: 1000,
debug: true,
};
document.addEventListener('DOMContentLoaded', function () {
var gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
var datasource = createDataSource();
gridOptions.api.setServerSideDatasource(datasource);
});
function createDataSource() {
return {
//rowCount: undefined,
getRows: (params) => {
console.log(`params start row:${params.startRow}, params end row: ${params.endRow}`);
var pagination = getPagination(params.startRow, params.endRow);
console.log(`asking for page ${pagination.page} and count ${pagination.count}`);
// send new request
fetch(`http://localhost:5000/api/tickets?page=${pagination.page}&count=${pagination.count}`)
.then((response) => response.json())
.then(data => {
console.log("data received");
console.log(data);
console.log(params);
params.success({
rowData: data.items,
rowCount: pagination.page * pagination.count,
});
//gridOptions.api.setRowCount(data.totalCount);
});
},
};
}
function getPagination(startRow, endRow){
let pagination = {
page: 1,
count: 10
};
if(startRow && endRow){
let size = endRow - startRow;
let page = Math.ceil(startRow / size);
pagination = {
page: page,
count: size
};
}
return pagination;
}
})();
I figured it out. The problem was in the row count itself (probably) as it needs to be set to the total existing count of items that exist in back-end, so that the grid knows that needs more.
Here's a possible solution.
For ag-grid Enterprise
(() => {
const gridOptions = {
columnDefs: [
{ valueGetter: 'node.rowIndex', maxWidth: 100 },
{ field: 'id', minWidth: 150 },
{ field: 'channel', minWidth: 150 },
{ field: 'subject', minWidth: 400 }
],
defaultColDef: {
flex: 1,
minWidth: 80,
},
rowModelType: 'serverSide',
serverSideInfiniteScroll: true,
cacheBlockSize: 10, //this is the count (page size)
maxBlocksInCache: 2,
rowBuffer: 0,
debug: false
};
document.addEventListener('DOMContentLoaded', function () {
var gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
var datasource = createDataSource();
gridOptions.api.setServerSideDatasource(datasource);
});
function createDataSource() {
return {
getRows: (params) => {
let count = params.request.endRow - params.request.startRow; // or the cacheBlockSize
let page = Math.ceil(params.request.endRow / count);
console.log(`asking for page ${page} and count ${count}`);
fetch(`http://localhost:5000/api/tickets?page=${page}&count=${count}`)
.then((response) => response.json())
.then(data => {
params.success({
rowData: data.items,
rowCount: data.totalCount,
});
});
},
};
}
})();
For ag-grid Community
A few things are different,
obviously the ag-grid library is a different one.
the row model type is infinite
the grid options api method to set datasource is called setDatasource
there is no object response within the injected getRows parameter, so the startRow and endRow are retrieved directly from the params object.
at index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>JavaScript example</title>
<meta charSet="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<style media="only screen">
html, body {
height: 100%;
width: 100%;
margin: 0;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
}
html {
position: absolute;
top: 0;
left: 0;
padding: 0;
overflow: auto;
}
body {
padding: 1rem;
overflow: auto;
}
</style>
</head>
<body>
<div id="myGrid" style="height: 100%" class="ag-theme-alpine-dark">
</div>
<script>var __basePath = './';</script>
<script src="https://unpkg.com/ag-grid-community/dist/ag-grid-community.min.js">
</script>
<script src="main.js">
</script>
</body>
</html>
at main.js
(() => {
const gridOptions = {
columnDefs: [
{ valueGetter: 'node.rowIndex', maxWidth: 100 },
{ field: 'id', minWidth: 150 },
{ field: 'channel', minWidth: 150 },
{ field: 'subject', minWidth: 400 }
],
defaultColDef: {
flex: 1,
minWidth: 80,
},
rowModelType: 'infinite',
cacheBlockSize: 10, //this is the count (page size)
maxBlocksInCache: 2,
rowBuffer: 0,
debug: false
};
document.addEventListener('DOMContentLoaded', function () {
var gridDiv = document.querySelector('#myGrid');
new agGrid.Grid(gridDiv, gridOptions);
var datasource = createDataSource();
gridOptions.api.setDatasource(datasource);
});
function createDataSource() {
return {
getRows: (params) => {
console.log(params);
let count = params.endRow - params.startRow; // or the cacheBlockSize
let page = Math.ceil(params.endRow / count);
console.log(`asking for page ${page} and count ${count}`);
fetch(`http://localhost:5000/api/tickets?page=${page}&count=${count}`) // any additional filter must be set on that url as query params
.then((response) => response.json())
.then(data => {
params.successCallback(data.items, data.totalCount);
});
},
};
}
})();

Yii2 stop page re-load while clicking on pagination

I have an index page in which I am calling some views based on a selection. Also, I have a form that is submitting on every sent request.
<section class="container-fluid">
<div class="box">
<div class="box-body">
<form action="index" method="post" >
<select required id="s" name="dtype" class="dropdown"
style="float: left; text-align: left;width: 20%; margin: 10px;">
<option value="400">Select Data Type</option>
<option value="401"<?php if(isset($_POST['dtype']) && $_POST['dtype'] == '401')
echo 'selected= "selected"';
?>>Current</option>
<option value="402"<?php if(isset($_POST['dtype']) && $_POST['dtype'] == '402')
echo 'selected= "selected"';
?>>Voltage</option>
<option value="403"<?php if(isset($_POST['dtype']) && $_POST['dtype'] == '403')
echo 'selected= "selected"';
?>>kWh</option>
</select>
<input style="float: left; text-align: left; margin: 10px; width: 15%" type="text" id="name" name="msn" required
minlength="4" maxlength="15" size="15" placeholder="MSN"
value="<?php echo isset($_POST['msn']) ? htmlspecialchars($_POST['msn'], ENT_QUOTES) : ''; ?>">
<?php
echo DateTimePicker::widget([
'name' => 'datetime_10',
'id'=>'start',
'value' => Yii::$app->request->post('datetime_10', null),
'options' => [
'placeholder' => 'Start',
'autocomplete' => 'off',
'required' =>true,
],
'convertFormat' => false,
'pluginOptions' => [
'format' => 'yyyy-mm-dd hh:i:ss',
//'startDate' => '01-Mar-2014 12:00 AM',
'todayHighlight' => true,
'autoclose' => true,
]
]);
echo DateTimePicker::widget([
'name' => 'datetime_11',
'id'=>'end',
'value' => Yii::$app->request->post('datetime_11', null),
'options' => [
'placeholder' => 'End',
'autocomplete' => 'off',
'required' =>true,
],
'convertFormat' => false,
'pluginOptions' => [
'format' => 'yyyy-mm-dd hh:i:ss',
//'startDate' => '01-Mar-2014 12:00 AM',
'todayHighlight' => true,
'autoclose' => true,
]
]);
?>
<input type="submit" value="Query" id="btnSubmit" class="btn btn-success pull-right" style="margin: 5px" />
</form>
</div>
</div>
</section>
<section class="content">
<div class="box">
<div class="box-body">
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<?php
if($type == '401')//current
{
$columns = [
[
'class' => 'yii\grid\SerialColumn',
],
'Device_ID',
'Customer_ID',
'MSN',
'Current_Phase_1',
'Current_Phase_2',
'Current_Phase_3',
'Data_Date_Time',
];
echo $this->render('_currentChart', [
'dataProvider' => $dataProvider,
]) ;
}else if($type == '402')//voltages
{
$columns = [
[
'class' => 'yii\grid\SerialColumn',
],
'Device_ID',
'Customer_ID',
'MSN',
'Voltage_Phase_1',
'Voltage_Phase_2',
'Voltage_Phase_3',
'Data_Date_Time',
];
echo $this->render('_voltageChart', [
'dataProvider' => $dataProvider,
]) ;
}
else if($type == "403")
{
$columns = [
[
'class' => 'yii\grid\SerialColumn',
],
'Device_ID',
'Customer_ID',
'MSN',
'kWh_Total',
'Data_Date_Time',
];
echo $this->render('_kwhChart', [
'dataProvider' => $dataProvider,
]) ;
}
else if($type == "404")
{
$columns = [
['class' => 'yii\grid\SerialColumn'],
'Device_ID',
'Customer_ID',
'MSN',
'Total_Power',
'Data_Time',
];
echo $this->render('_totalChart', [
'dataProvider' => $dataProvider,
]) ;
}
else
{
$columns = [
['class' => 'yii\grid\SerialColumn'],
'device_id',
'cust_id',
'msn',
'kwh_t',
'voltage_p1',
'voltage_p2',
'voltage_p3',
'current_p1',
'current_p2',
'current_p3',
'data_date_time',
];
}
?>
<?=
GridView::widget([
'dataProvider' => $dataProvider,
//'filterModel' => $searchModel,
'columns' => $columns
]);
?>
</div>
</div>
</section>
Current Chart
<?PHP
$dataPointsC1 = array();
$dataPointsC2 = array();
$dataPointsC3 = array();
$model = $dataProvider->getModels();
foreach ($model as $row){
// pushing for voltages
array_push($dataPointsC1, array("label"=>$row['Data_Date_Time'],"y"=>$row['Current_Phase_1']));
array_push($dataPointsC2, array("label"=>$row['Data_Date_Time'],"y"=>$row['Current_Phase_2']));
array_push($dataPointsC3, array("label"=>$row['Data_Date_Time'],"y"=>$row['Current_Phase_3']));
}
?>
<div id="chartContainer1" style="width: 100%; height: 300px;display: inline-block;">
</div>
<script>
var chart1 = new CanvasJS.Chart("chartContainer1", {
exportEnabled: true,
animationEnabled: true,
zoomEnabled: true,
theme: "light1",
title:{
text: "Current"
},
legend:{
cursor: "pointer",
verticalAlign: "bottom",
horizontalAlign: "center",
itemclick: toggleDataSeries
},
data: [
{
type: "line",
//lineColor:"yellow",
// legendMarkerColor: "yellow",
name: "Current(Phase-1)",
indexLabel: "{y}",
//yValueFormatString: "V1#0.##",
showInLegend: true,
dataPoints: <?php echo json_encode($dataPointsC1, JSON_NUMERIC_CHECK); ?>
},
{
type: "line",
// lineColor:"orange",
// legendMarkerColor: "orange",
name: "Current(Phase-2)",
indexLabel: "{y}",
//yValueFormatString: "V2#0.##",
showInLegend: true,
dataPoints: <?php echo json_encode($dataPointsC2, JSON_NUMERIC_CHECK); ?>
},
{
type: "line",
// lineColor:"purple",
// legendMarkerColor: "purple",
name: "Current(Phase-3)",
indexLabel: "{y}",
//yValueFormatString: "V3#0.##",
showInLegend: true,
dataPoints: <?php echo json_encode($dataPointsC3, JSON_NUMERIC_CHECK); ?>
}
]
});
chart1.render();
function toggleDataSeries(e){
e.dataSeries.visible = !(typeof (e.dataSeries.visible) === "undefined" || e.dataSeries.visible);
chart1.render();
}
</script>
Screen before any filter
Screen After filter
The pages also come with pagination. When I click on the pagination the entire page reloads and sets to it's original state.
How can I manage this ?
use pjax
https://www.yiiframework.com/doc/api/2.0/yii-widgets-pjax
in your index view
Pjax::begin();
//your reload code
Pjax::end();

Vuetify v-data-table search.filter not showing any results

Getting data back from our API but built in Vuetify search/filter is not working. I think it has to do with the data coming back being nested in an object. When typing in the search filter i get "No matching records found" after the first character, when removing the search term the full data table is displayed. Thanks in advance for any help.
<template>
<v-container
fill-height
fluid
grid-list-xl
>
<v-layout
justify-center
wrap
>
<v-flex
md6
>
<material-card
color="black"
title="Users"
>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
<v-data-table
:headers="headers"
:items="userData"
:search="search"
hide-actions
>
<template
slot="headerCell"
slot-scope="{ header }"
>
<span
class="subheading font-weight-light text-dark text--darken-3"
v-text="header.text"
/>
</template>
<template
slot="items"
slot-scope="{ item }"
>
<td>
<v-avatar slot="offset" class="mx-auto d-block" size="100">
<img v-if="item.ProfileImage==null" src="img/conectrlogo.jpg">
<img v-else v-bind:src= "item.ProfileImage">
</v-avatar></td>
<td><v-btn text-small outlined color="primary" #click= "goToUserProfile(item.Id)">{{ item.Id}}</v-btn></td>
<td>{{ item.Username}}</td>
<td>{{ item.Name}}</td>
</template>
</v-data-table>
</material-card>
</v-flex>
</v-layout>
</v-container>
</template>
Script
<script>
import axios from 'axios'
export default {
mounted()
{
console.log("got into mounted function");
this.getResults();
},
data () {
return {
customFilter: function (items, search, filter, headers) {
search = search.toString().toLowerCase()
if (search.trim() === '') return items
const props = headers.map(h => h.value)
return items.filter(item => props.some(prop => filter(getObjectValueByPath(item, prop, item[prop]), search)))
},
userData:[],
totalUsers:0,
showResults:true,
search:'',
headers:[
{
text: 'User',
value: 'profileimage',
align: 'center',
width: '50px',
sortable:false
},
{
text: 'id',
value: 'id',
align: 'center',
width: '100px',
sortable:false
},
{
text: 'Username', value: 'username',
align: 'left',
sortable: false,
width: '50px'
},
{
text: 'Name', value: 'name',
align: 'left',
sortable: true,
width: '50px'
}
]
}
},
computed:{
},
methods: {
goToUserProfile: function(Id)
{
console.log("avatar clicked:"+Id);
this.$router.push('/user-profile/'+Id)
},
getResults (){
console.log("got into the all users endpoint");
console.log(this.$baseUrl+'/admin/users');
// axios.get(this.$baseUrl+'/admin/users',
// {withCredentials: true}).then ( response => {
// this.userData=response.data.Users;
// this.totalUsers = response.data.UserCount;
// console.log("all user response:"+this.userData);
// });
//this.showResults=true;
axios.defaults.withCredentials = true;
axios(this.$baseUrl+'/admin/users', {
method: 'GET',
withCredentials: true,
crossDomain:true
}).then(res => {
console.log(res);
this.userData=res.data.Users;
this.totalUsers = res.data.UserCount;
console.log("all user response:"+this.userData);
}).catch(err => {
console.log("got an error");
console.log(err);
})
},
initialize()
{
},
}
}
</script>

Sorting calculated fields in Yii2 (Grid View) getter param

How get i sort my rows by field i get from model getter like this
* Returns the score for this team
*/
public function getScore() {
$score = 0;
if (!empty($this->bonus_points)) {
$score += $this->bonus_points;
}
foreach (Attempt::find()->where(['team_id' => $this->id, 'marked' => 1])->all() as $attempt) {
$score -= $attempt->cost;
$score += $attempt->reward;
}
return $score;
}
View Code
GridView::widget([
'id' => 'quickfire-grid',
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'filterPosition' => GridView::FILTER_POS_HEADER,
'tableOptions' => [
'class' => 'table'
],
'layout' => "{summary}\n{items}\n{pager}",
'columns' => [
['class' => 'yii\grid\CheckboxColumn'],
'name',
[
'attribute' => 'bonus_points',
'label' => 'Adjustment',
'filter' => false
],
[
'attribute' => 'score',
'label' => 'Score',
'filter' => false,
],
[
'label' => 'Adjust score',
'format' => 'raw',
'value' => function ($data) use ($game) {
return Html::input('text', 'score-' . $data->id, '0', ['id' => 'score-' . $data->id]) . ' ' . Html::a('Adjust score', '#', ['class' => 'btn btn-danger btn-adjust-score', 'data-team-id' => $data->id, 'data-href' => Url::toRoute(['adjust-scores', 'game_id' => $game->id, 'skipConfirmation' => true])]);
},
],
],
]);
Is it possible to sort grid by score field ? I think need to add some javascript code. I have read this article but there is no solution https://www.yiiframework.com/wiki/621/filter-sort-by-calculatedrelated-fields-in-gridview-yii-2-0.
Team::find()->select(['total_score' => 'ifnull(s.score, 0)+team.bonus_points'])
->leftJoin([
's' => Attempt::find()
->select('team_id, SUM(reward-cost) as score')
->where(['marked' => 1])
->groupBy('team_id')
], 's.team_id=team.id')
->orderBy('total_score')
Something like this) Modify select with your needs...

Insertion text box into custom Telerik Kendo Filter

I want to create a Custom Filter for Ages of the Patients (their age can be in years, months and days). The code is:
#(Html.Kendo().Grid<RunSummary>()
.Name("Runs")
.DataSource(datasource => datasource
.Ajax().PageSize(25)
.Sort(sort => sort.Add("TimeOn").Descending())
.Read(read => read.Action("GetRunSummaries", "Home")))
.Columns(columns =>
{
columns.Bound(d => d.RunId).Title("").Width(30).Filterable(false)
.ClientTemplate("<input type='checkbox' unlock='true' class='primaryBox' id='#= RunId #' />").Visible(User.IsInRole("Registry Administrator"));
columns.Bound(c => c.UniqueId).Title(ELSORegistry.Resources.Views.Home.HomeStrings.UniqueId);
columns.Bound(c => c.RunNo).Title(SharedStrings.Run);
columns.Bound(c => c.Birthdate).Title(SharedStrings.Birthdate).Format("{0:g}").Filterable(true);
//columns.Bound(c => c.Age).Title(SharedStrings.Age).ClientTemplate("#= formatAge(Age)#");
columns.Bound(c => c.Age).Title(SharedStrings.Age)
.ClientTemplate("#= formatAge(Age)#")
.Filterable(
filterable => filterable
.UI("cityFilter")
.Extra(false)
.Operators(operators => operators
.ForNumber(str => str.Clear().IsEqualTo("Is equal to").IsGreaterThan("Is greater than").IsLessThan("Is less than"))
)
);
columns.Bound(c => c.TimeOn).Title(PatientStrings.TimeOn)
.Format("{0:g}")
.Filterable(true);
columns.Bound(c => c.TimeOff).Title(PatientStrings.TimeOff)
.Format("{0:g}")
.Filterable(true);
columns.Bound(c => c.isLocked).Title("Locked").ClientTemplate("#= isLocked ? 'Yes' : 'No' #");
//columns.Bound(p => p.Abbreviation).Title("Mode");
columns.Command(command => command.Custom("Patient").Click("selectPatient"));
columns.Command(command => command.Custom("Run").Click("selectRun"));
}
)
.Pageable(p => p.PageSizes(new[] {10, 25, 50, 100}))
.Sortable()
.Filterable( )
.Events( e => e.FilterMenuInit("FilterMenuFunc") ) // apply x [closing box] on pop up filter box
)
</section>
<script>
function cityFilter(element) {
element.kendoDropDownList({
dataSource: [{ Name: "Days", Value: "1" }, { Name: "Months", Value: "2" }, { Name: "Years", Value: "3" }]
, dataTextField: "Name"
, dataValueField: "Value"
});
window.setTimeout(function () {
element.data("kendoDropDownList").value("3");
}, 1);
}
</script>
I have to insert a text box into Age filter, to put here number (of Ages). How to insert text box field into the Custom Filter? Thank you in advance for any help.
The possible solution is:
function AgeFilter(element) {
element.kendoDropDownList({
dataSource: [{ Name: "Days", Value: "1" }, { Name: "Months", Value: "2" }, { Name: "Years", Value: "3" }]
, dataTextField: "Name"
, dataValueField: "Value"
});
window.setTimeout(function () {
element.data("kendoDropDownList").value("1");
}, 1);
and in the grid:
columns.Bound(c => c.customAge).Title(SharedStrings.Age)
.Filterable(
filterable => filterable
.UI("AgeFilter")
.Extra(false)
.Operators(operators => operators
.ForString(str => str.Clear().IsEqualTo("Is equal to"))
)
);
}

Resources