ParamQuery grid (PQGrid) Add new row to nested grid - asp.net

I am using Paramquery grid and I need to add new row to the detail grid, the new row should be added to the child of the current row.
I tried this :
toolbar: {
items: [
{
type: 'button', icon: 'ui-icon-plus', label: 'New', listener:
{
"click": function (evt, ui) {
debugger;
var $gridDet = $("#grid_editing").pqGrid("option", "detailModel");
//append empty row at the end.
var rowData = { ID: "2", 'Name':'Has'}; //empty row
var rowIndx = $gridDet.pqGrid("addRow", { rowData: rowData, checkEditable: true });
$gridDet.pqGrid("goToPage", { rowIndx: rowIndx });
$gridDet.pqGrid("editFirstCellInRow", { rowIndx: rowIndx });
}
}
}
]
An error thrown: $gridDet.pqGrid is not a function (The line that starts with rowIndx throws the error)
Please check the image below to see mygrid structure.

You can get the grid using:
var $gridDet = $(this).closest('.pq-grid');
and then apply the add logic to it.

Related

Vue doesn't update when computed data change

Context: I have a list of posts with tags, categories from wordpress api. I display these posts with Vue and using computed with a search box to filter the result based on titre, description, tags, and categories
Problem: I am trying to update a computed list when user click on a list of tag available. I add the get and set for computed data like this:
var vm = new Vue({
el: '#blogs',
data: {
search: '',
posts: [],
filterPosts: []
},
beforeMount: function() {
// It should call the data and update
callData();
},
computed: {
filterPosts: {
get: function() {
var self = this;
return self.posts.filter(function(post){
var query = self.search.toLowerCase();
var title = post.title.toLowerCase();
var content = post.content.toLowerCase();
var date = post.date.toLowerCase();
var categories = '';
post.categories.forEach(function(category) {
categories += category.name.toLowerCase();
});
var tags = '';
post.tags.forEach(function(tag){
tags += tag.name.toLowerCase();
});
return title.indexOf(query) !== -1 ||content.indexOf(query) !== -1 || date.indexOf(query) !== -1 || categories.indexOf(query) !== -1 || tags.indexOf(query) !== -1;
});
},
set: function (newValue) {
console.log(newValue);
this.filterPosts = Object.assign({}, newValue);
}
}
},
methods: {
filterByTag: function(tag, event) {
event.preventDefault();
var self = this;
self.filterPosts = self.posts.filter(function(post){
var tags = '';
post.tags.forEach(function(tag){
tags += tag.name.toLowerCase();
});
return tags.indexOf(tag.toLowerCase()) !== -1;
});
}
}
}); // Vue instance
The console.log always output new data based on the function I wrote on methods but Vue didn't re-render the view. I think I didn't do the right way or thought like Vue. Could you please give some insight?
Edit 1
Add full code.
I tried to add filterPosts in data but I received this error from Vue: The computed property "filterPosts" is already defined in data.
Your setter is actually not setting anything, it only logs the new value. You need to store it somewhere.
For example you can store it in the component's data:
data: {
value: 'foo',
},
computed: {
otherValue: {
get() { /*...*/ },
set(newVal) { this.value = newVal },
},
},
But this is definitely not the only possibility, if you use Vuex, the setter can dispatch an action that will then make the computed value get updated. The component will eventually catch the update and show the new value.
computed: {
value: {
get() {
return this.$store.getters.externalData;
},
set(newVal) {
return this.$store.dispatch('modifyingAction', newVal);
},
},
},
The bottomline is you have to trigger a data change in the setter, otherwise your component will not be updated nor will it trigger any rerender.
EDIT (The original answer was updated with full code):
The answer is that unless you want to manually change the list filteredPosts without altering posts, you don't need a get and set function for your computed variable. The behaviour you want can be acheived with this:
const vm = new Vue({
data() {
return {
search: '',
posts: [],
// these should probably be props, or you won't be able to edit the list easily. The result is the same anyway.
};
},
computed: {
filteredPosts() {
return this.posts.filter(function(post) {
... // do the filtering
});
},
},
template: "<ul><li v-for='post in filteredPosts'>{{ post.content }}</li></ul>",
});
This way, if you change the posts or the search variable in data, filteredPosts will get recomputed, and a re-render will be triggered.
After going around and around, I found a solution, I think it may be the right way with Vue now: Update the computed data through its dependencies properties or data.
The set method didn't work for this case so I add an activeTag in data, when I click on a tag, it will change the activeTag and notify the computed filterPost recheck and re-render. Please tell me if we have another way to update the computed data.
var vm = new Vue({
el: '#blogs',
data: {
search: '',
posts: [],
tags: [],
activeTag: ''
},
beforeMount: function() {
// It should call the data and update
callData();
},
computed: {
filterPosts: {
get: function() {
var self = this;
return self.posts.filter(function(post){
var query = self.search.toLowerCase();
var title = post.title.toLowerCase();
var content = post.content.toLowerCase();
var date = post.date.toLowerCase();
var categories = '';
post.categories.forEach(function(category) {
categories += category.name.toLowerCase();
});
var tags = '';
post.tags.forEach(function(tag){
tags += tag.name.toLowerCase();
});
var activeTag = self.activeTag;
if (activeTag !== '') {
return tags.indexOf(activeTag.toLowerCase()) !== -1;
}else{
return title.indexOf(query) !== -1 ||content.indexOf(query) !== -1 || date.indexOf(query) !== -1 || categories.indexOf(query) !== -1 || tags.indexOf(query) !== -1;
}
});
},
set: function (newValue) {
console.log(newValue);
}
}
},
methods: {
filterByTag: function(tag, event) {
event.preventDefault();
var self = this;
self.activeTag = tag;
}
}
}); // Vue instance
Try something like:
data: {
myValue: 'OK'
},
computed: {
filterPosts: {
get: function () {
return this.myValue + ' is OK'
}
set: function (newValue) {
this.myValue = newValue
}
}
}
More:
https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter

font-awesome icon in display of combobox extjs 6

I tried several ways to set an icon, in the displayfield, when an item of the combo is selected with not luck, this is the fiddle for anyone to want try to help with this. very much appreciated any light.
fiddle example
The only solution is to transform the input type combo in a div with this:
fieldSubTpl: [
'<div class="{hiddenDataCls}" role="presentation"></div>',
'<div id="{id}" type="{type}" style="background-color:white; font-size:1.1em; line-height: 2.1em;" ',
'<tpl if="size">size="{size}" </tpl>',
'<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
'class="{fieldCls} {typeCls}" autocomplete="off"></div>',
'<div id="{cmpId}-triggerWrap" class="{triggerWrapCls}" role="presentation">',
'{triggerEl}',
'<div class="{clearCls}" role="presentation"></div>',
'</div>', {
compiled: true,
disableFormats: true
}
],
Override the setRawValue method of the combo like this:
setRawValue: function (value) {
var me = this;
me.rawValue = value;
// Some Field subclasses may not render an inputEl
if (me.inputEl) {
// me.inputEl.dom.value = value;
// use innerHTML
me.inputEl.dom.innerHTML = value;
}
return value;
},
and style your fake combo div like you want.
Thats because an input on HTML can't have HTML like value inside it.
Keep attenction, the get Value method will return you the HTML inside the div, and maybe you should also override it, but thats the only one method.
You will be able to get the selected value with this method:
Ext.fly(combo.getId()+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
If I were you I would like to do something like this:
combo.getMyValue();
So add this property to your combo:
getMyValue:function(){
var combo=this;
if(Ext.fly(combo.id+'-inputEl'))
return Ext.fly(combo.id+'-inputEl').dom.innerHTML.replace(/<(.|\n)*?>/gm, '');
},
Here is a working fiddle
Perhaps my solution is similar to a hack, but it works in 6.7.0 and is a bit simpler.
Tested in Chrome. Theme - Material. For another theme will require minor improvements.
Sencha Fiddle live example
Ext.application({
name: 'Fiddle',
launch: function () {
var store = new Ext.data.Store({
fields: [{
name: 'class',
convert: function (value, model) {
if (value && model) {
var name = value
.replace(/(-o-)|(-o$)/g, '-outlined-')
.replace(/-/g, ' ')
.slice(3)
.trim();
model.data.name = name.charAt(0).toUpperCase() + name.slice(1);
return value;
}
}
}, {
name: 'name'
}],
data: [{
class: 'fa-address-book'
}, {
class: 'fa-address-book-o'
}, {
class: 'fa-address-card'
}]
});
var form = Ext.create('Ext.form.Panel', {
fullscreen: true,
referenceHolder: true,
items: [{
xtype: 'combobox',
id: 'iconcombo',
queryMode: 'local',
editable: false,
width: 300,
valueField: 'class',
displayField: 'name',
store: store,
itemTpl: '<div><i class="fa {class}"></i> {name}</div>',
afterRender: () => {
var component = Ext.getCmp('iconcombo');
var element = document.createElement('div');
element.className = 'x-input-el';
element.addEventListener('click', () => component.expand());
component.inputElement.parent().dom.prepend(element);
component.inputElement.hide();
component.addListener(
'change', (me, newValue, oldValue) => {
component.updateInputValue.call(me, newValue, oldValue);
},
component
);
var method = component.updateInputValue;
component.updateInputValue = (value, oldValue) => {
method.call(component, value, oldValue);
var selection = component.getSelection();
if (selection) {
element.innerHTML =
'<div><i class="fa ' + selection.get('class') + '"></i> ' + selection.get('name') + '</div>';
}
};
}
}, {
xtype: 'button',
text: 'getValue',
margin: '30 0 0 0',
handler: function (component) {
var combo = Ext.getCmp('iconcombo');
alert(combo.getValue());
}
}]
});
form.show();
}
});

ExtJS : move a record in a grid

I have a simple grid on ExtJS and would like the user to be able to move the record from its original position.
When the user double clicks on a record, a small window containing a combobox appears, he can choose a value on the combobox and then click the save button to apply the change.
However, it doesn't work, I've searched many solutions for this on different forums and none seems to work. Either nothing happens, or an undefined row is added at the end of the grid. Here is the base code I use :
onEditRank: function(view, cell, cellIndex, record, row, rowIndex, e)
{
var reditor = Ext.create('CMS.view.Views.RankEditor', {id: 'reditorView'});
var form = reditor.down('form');
var oldPos = this.getFlatrq().getView().indexOf(record);
var grStore = this.getGridRnkStoreStore();
var i;
var data = [];
for(i = 1; i <= CMS.global.Variables.limit + 1; i++)
{
data.push(i);
}
var combo = Ext.create
(
'Ext.form.field.ComboBox',
{
fieldLabel: 'Rank',
itemId: 'cmbRank',
store: data
}
);
var saveRnk = Ext.create
(
'Ext.button.Button',
{
text: 'Save',
handler: function()
{
}
}
);
form.add(combo);
form.add(saveRnk);
reditor.show();
}
Now here are the different handlers I have tried for my save button :
handler: function()
{
grStore.remove(record);
grStore.insert(record, combo.getValue() - 1);
this.up('form').up('window').close();
}
handler: function()
{
grStore.removeAt(oldPos);
grStore.insert(record, combo.getValue() - 1);
this.up('form').up('window').close();
}
handler: function()
{
var rec = grStore.getAt(oldPos).copy();
grStore.removeAt(oldPos);
grStore.insert(rec, combo.getValue() - 1);
this.up('form').up('window').close();
}
Those 3 handlers inserted undefined rows at the end of my grid. I displayed the values of oldPos and combo.getValue() and they are correct, I also displayed the record variable before and after the remove because I thought it might be destroyed but it wasn't. I have also tried to add a move function to store and call it :
'CMS.store.GridRnkStore',
{
extend: 'Ext.data.Store',
model: 'CMS.model.GridRnkModel',
autoLoad: false,
filterOnLoad: true,
autoSync: true,
move: function(from, to)
{
console.log(from + " " + to);
var r = this.getAt(from);
this.data.removeAt(from);
this.data.insert(to, r);
this.fireEvent("move", this, from, to);
},
}
);
But it didn't work either, it did nothing actually (I put some console.log in the move function to see if it was called and it was, with the right parameters). I'm running out of ideas, any help would be appreciated.
Thank you.
try to set the private move parameter to true of store.remove():
remove: function(records, /* private */ isMove, silent)

Unique Dropdownlist is coming for the first page values in Jqgrid

Hello Every One!!!
I added codes for getting unique dropdownlist in the columns of jqgrid .
Dropdownlist is coming but it is coming for the first page of the jqgrid means that dropdownlist has the unique values of the first page of the jqgrid whereas i need all the unique values of the whole Jqgrid..
Below I am posting my codes...
grid = $("#gridId");
getUniqueNames = function (columnName) {
var texts = grid.jqGrid('getCol', columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i = 0; i < textsLength; i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
},
buildSearchSelect = function (uniqueNames) {
var values = ":All";
$.each(uniqueNames, function () {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function (columnName) {
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value: buildSearchSelect(getUniqueNames(columnName)),
sopt: ['eq']
}
}
);
};
This function i have called like this...
setSearchSelect('extension');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt: ['cn'],
dataInit: function (elem) {
$(elem).autocomplete({
source: getUniqueNames('Name'),
delay: 0,
minLength: 0
});
}
}
});
setSearchSelect('username');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt: ['cn'],
dataInit: function (elem) {
$(elem).autocomplete({
source: getUniqueNames('Name'),
delay: 0,
minLength: 0
});
}
}
});
In between these two code snippets I am loading data into jqgrid locally using Ajax call.
Any help will be heartely appreciated..
Thanx in advance..
I belive getCol will return only currently loaded data from jqgrid (for defined column).
Because at first you load just first page, autocomplete has no way of knowing unique values of column for more than that!
You will have to either load all pages at once (small dataset) or
fill autocomplete from database.

Extjs4 how to remove duplicated rows from a grid?

My_grid contains many duplicated rows (same name and username, and with different hidden id). How to remove duplicated rows?
you should set the idProperty of your proxy's reader or on your model.
var myStore = Ext.create('Ext.data.Store', {
proxy: {
type: 'ajax',
url: '/myUrl',
reader: {
idProperty: 'Id'
}
},
model: 'myModel'
});
This snippet works for you hopefully:
It's important that you declared your store and grid with this.
For example this.store = ...
//Listener on the button removes the duplicated rows
this.button.on('click', function() {
this.store.each(function(record) {
//This is necessary because if this record was removed before
if(record !== undefined) {
//Find all records which have the same name like this record
var records = record.store.query('name', record.get('name'));
//Remove all found records expect the first record
records = records.each(function(item, index) {
//Don't delete the first record
if(index != 0) {
item.store.remove(item);
}
});
}
});
}, this);

Resources