I am trying to get dataView.collapseAllGroups() to work with SlickGrid.
The post In SlickGrid, how do I collapse grouping via javascript says to just use collapseAllGroups() but it doesn't seem to work.
Even when going to the current demo page http://mleibman.github.io/SlickGrid/examples/example5-collapsing.html and typing dataView.collapseAllGroups() into the console, it doesn't seem to do anything. Is there something else that I need to do to refresh the grid?
Edit
I was trying to get the Grid to display a tree where the groups are collapsed by default. Although I cannot get CollapseAllGroups() to work, I was able to do a hack by adding "if (item._collapsed == null) item._collapsed = true;" to myFilter function that is in the example above.
This is a rough worksound but it does the job for now until I find the real solution:
function myFilter(item) {
// Added this line:
if (item._collapsed == null) item._collapsed = true;
if (item.parent != null) {
var parent = gridData[item.parent];
while (parent) {
if (parent._collapsed) {
return false;
}
parent = gridData[parent.parent];
}
}
return true;
}
That particular example demonstrates how to implement hierarchies using custom formatters and a filter. It does NOT use the DataView's grouping feature, so the collapseAllGroups() call has no effect.
Related
I'm using Cypress for my automated tests. I'm trying to find a product on a page and click on it. If the product not displayed on the page, go to the next one until it is found.
I've been trying a lot of things already: while loop, each loop, simple cy.get but none of them work. Can anyone help me to solve this?
You'll need a recursive command, implementation of which will depend on your specific scenario. There's no one-size-fits-all solution, but generally it will look something like this:
function findElem ( targetSelector ) {
// first, we need to query a container (could be table, or a generic item
// container). The important thing is, this container must exist on every
// page you'll traverse.
cy.get('.someContainer').then( $container => {
// synchronously find the target element, however you want. In this
// example I use an attribute selector, but you can do whatever you
// want.
if ( $container.find(targetSelector).length ) {
return true;
} else {
return false;
}
}).then( found => {
if ( found ) {
return cy.log(`found elem "${targetSelector}"`);
} else {
// synchronously check if there's a next page/table
if ( Cypress.$('.nextPageButton').length ) {
// when know that there is a next page, click it using cypress
cy.get('.nextPageButton').click();
// here, assert that next page/table is loaded, possibly by
// asserting that current page/table is removed from DOM
// then, recurse
return findElem(targetSelector);
} else {
throw new Error(`Couldn't find elem "${targetSelector}" on any page`);
}
}
});
}
it('test', () => {
findElem(`[data-id="42"]`);
});
The crux of the solution is using a combination of commands to query a container, and synchronous inspection (using jQuery or whatever) to find the actual element. Learn more at Conditional Testing.
For a concrete implementation, you can refer to an older answer I gave to a similar question.
What are the best form validation practice for Vue? I've been using simple if tree in a method for validation disabled attribute of the send button but even with just two fields it may already be many cases to validate and given I have different forms I have to copypaste a lot
Here is method I use for one of modal windows:
isCryptoWithdrawalPossible() {
if (this.sendWalletModal.amount || this.sendWalletModal.address) {
if (this.sendWalletModal.amount && !this.sendWalletModal.address) {
this.sendWalletModal.error = this.$t('wallets.wallets.needAddress');
return false;
} else if (!this.sendWalletModal.amount && this.sendWalletModal.address) {
this.sendWalletModal.error = this.$t('wallets.wallets.needAmount')
return false;
}
if (this.sendWalletModal.amount < this.sendWalletModal.method.minAmount) {
this.sendWalletModal.error = this.$t('wallets.wallets.overLimitMinAmount', [this.sendWalletModal.method.minAmount]);
return false;
}
else if (this.sendWalletModal.amount > this.sendWalletModal.method.maxAmount) {
this.sendWalletModal.error = this.$t('wallets.wallets.overLimitMaxAmount', [this.sendWalletModal.method.maxAmount]);
return false;
}
else if (this.sendWalletModal.amount > this.filteredWallets.find( el => el.currencyTitle == this.sendWalletModal.currency).avaliableFunds - this.calculateSendFee(this.sendWalletModal)) {
this.sendWalletModal.error = this.$t('wallets.wallets.insufficientBalance')
return false;
}
else {
this.sendWalletModal.error = '';
return true;
}
} else {
this.sendWalletModal.error = '';
return false;
}
},
Check Vuelidate if you're looking for a third party lib to handle validations simply
Update Jan 2020: here is a nice overview of vuelidate - which is kinda compared to vee-validate (i would like to have had someone very familar with vee-validate show some more of its features but as an intro to vuelidate I liked the presentation). https://www.vuemastery.com/conferences/connect-tech-2019/vue-form-validation
Vuelidate on github: (https://github.com/vuelidate/vuelidate). Until now vee-validate has been better supported, but perhaps vuelidate have themselves better organised having been under transition for a while.
Also you can take a look at this link: https://laracasts.com/discuss/channels/vue/vue-validator-vs-vee-validate-vs
We use vee-validate where I work, vee-validate's home page is here: https://baianat.github.io/vee-validate/ .
It has a nice example sandbox here: https://baianat.github.io/vee-validate/examples/ .
I would recommend taking a look at the flags example in the codesandbox to see how vee-validate tracks changes on fields that it is validating.
It uses date-fns as it's default date library (which may be a concern for you if you are using moment, but I use both date-fns and moment dates with vee-validate (I use the "custom rules" feature for the moment dates)).
Once vee-validate is applied to your various form fields you can check to see if any of the fields have changed by calling a function as such:
hasChanged: function() {
return Object.keys(this.fields).some(key => this.fields[key].changed);
}
I have had issues with vee-validate, especially around dates, but it appears to be one of the better validation libraries out there for vue -and it appears to me that it is currently easier to get answers if you run into problems(this opinion will be biased because I have used vee-validate as against other libraries). One of the issues with vee-validate appears to be that if you change a field and then change it back to its original value then the field is still marked as changed -so you have to track initial values and current values yourself. But in many form scenarios you have to manually track hasChanged yourself anyway, for example if you decide that viewing a form changes the status of the data (from not viewed to viewed for example) then you will need to manually record the change of a "myFormViewed" variable which is unrelated-to/outside-of the form fields.
This is my example: enter link description here
How to reload automatically?
beforeProcessing: function (data, status, xhr) {
if (data.rows === '') {
$('#jqGridPreparate').jqGrid('clearGridData');
return false;
}
if (data.inputCol) {
$("td.ui-search-input input#id_prep").val('');
$("td.ui-search-input input#id_opisanie").val(data.inputCol);
var rplc = $.parseJSON($("#jqGridPreparate")[0].p.postData.filters);
for (var i=0; i < rplc.rules.length; i++) {
if (rplc.rules[i].field === 'prep') {
rplc.rules[i].field = 'opisanie';
}
}
$.extend($("#jqGridPreparate")[0].p.postData,{filters:JSON.stringify(rplc)});
$("#jqGridPreparate")[0].triggerToolbar(); // not WORK
}
}
I'm not sure that I full understand what you want to implement. I can guess that you want to apply the filter if some additional information will returned by from the server.
It seems that you implemented some custom agreement between jqGrid and the server about returned data. rows part of the server response should be array of items. In your case the server could set empty string as the value of rows instead. You try to use inputCol property of the server response to force filtering of previously loaded data. You makes some custom modifications of existing filter, you fill some fields of the filter toolbar and finally you try to use triggerToolbar. The code is very unclear and it contains a lot of assumptions which you don't described directly. It's not clear for me whether you want to start local filtering or jqGrid should send new request to the server with modified filter.
In any way, if you want to start some kind of reloading/filtering inside of other callback function, you shuld take in consideration some basic rules. First of all the method triggerToolbar or triggering reloadGrid works synchronously. It means that jqGrid first makes triggerToolbar, which makes reloadGrid, till the end and then will be executed the next line of code after $("#jqGridPreparate")[0].triggerToolbar();. Because of that it's strictly recommended to place all calls of triggerToolbar or reloadGrid inside of setTimeout body. It allows to process the current callback til the end and only then to make reloading. If the response from the server contains your custom information instead of typical jqGrid data then you should return false from beforeProcessing to stop the standard processing.
If you can construct postData.filters then you don't need to use triggerToolbar to apply the filter. Instead of that you need just set search: true parameter of jqGrid additionally and just trigger reloadGrid.
The corresponding code could be about the following:
beforeProcessing: function (data, status, xhr) {
var $self = $(this), p = $self.jqGrid("getGridParam");
if (data.rows === "") {
$self.jqGrid("clearGridData");
return false; // don't process the data by jqGrid
}
if (data.inputCol) {
var i, rplc = $.parseJSON(p.postData.filters);
for (i = 0; i < rplc.rules.length; i++) {
if (rplc.rules[i].field === "prep") {
rplc.rules[i].field = "opisanie";
}
}
p.postData.filters = JSON.stringify(rplc);
setTimeout(function () {
// apply the filter
p.search = true;
$self.trigger("reloadGrid", [{page: 1}]);
}, 50);
return false; // don't process the data by jqGrid
}
}
I have a mobile app that receives a push notification, when it does, I know there is a row that that needs to be updated. I have tried two methods for retrieving just that one:
var row = data_source.get(<id>);
row.dirty = true;
data_source.sync();
This tries to fire an UPDATE, which I could shoe-horn into doing what I want, but it's conceptually wrong.
The other option that I have tried:
data_source.read( { id : <id> } );
Which fires off a READ request, with the ID in options.data. When I try to hook this up, kendo complains about not getting an array back, and when I make the response into an array, it doesn't seem to work either.
How am I supposed to do this? GET it outside the context of the DataSource, and set the relevant parts, and then set the dirty bit to false?
Kendo doesn't do single row read out of the box. If its not feasible to do full read(), you have to do what you proposed. Try following :
1) make your server side read method to accept requests with or without id, without to read all items, with to read your one row.
2) use parameter map together with isPushNotificaton flag to control the read request params
parameterMap: function(data, type) {
if (type == "read") {
if (isPushNotificaton)
return { id : yourId };
else
return { id : 0}; // get all
}
}
3) use requestEnd to decide how to deal with read result
requestEnd: function(e) {
var type = e.type;
if (e.type == 'read') {
// examine the response(by count/add additional flags into response object)
var isFullReadResponse = ...;
if (!isFullReadResponse) {
// DIY
e.preventDefault();
UpdateSingleRow(response, datasource.data());
}
}
}
4) Implement UpdateSingleRow method as you proposed - .."and set the relevant parts, and then set the dirty bit to false", (Refresh a single Kendo grid row)
I was wondering if anyone was aware of an example that shows multiple listeners to the YUI DDProxy, DD, or DDTarget onDragDrop event. Currently I have a hacked up example going. I'm using the http://developer.yahoo.com/yui/examples/datatable/dt_ddrows.html'>DataTable Reorder Rows example. I've modified it into several js classes. One object they override DDProxy for handles the onDragDrop event but it seems that if it's handled here then nothing else catches the event. Check the snip:
YAHOO.extend(YAHOO.example.DDRows, YAHOO.util.DDProxy, {
//snip
onDragDrop: function(e, id) {
if (id == "right-function-pane") {
alert("In the right drop place");
YAHOO.util.DragDropMgr.refreshCache();
}
}
In a class that does the creation of DDRows, I want to listen to the event here as well. Some actions are more appropriate in some places. I want to listen to the event in both places. Here's what I'm doing in class that builds the above:
onDropHandler: function(e, id) {
DragDropTable.myDataTable.deleteRow(YAHOO.util.DragDropMgr.dragCurrent.id);
},
rowInitializer: function() {
var i, id, myDDRow,
allRows = DragDropTable.myDataTable.getTbodyEl().rows;
for (i = 0; i < allRows.length; i++) {
id = allRows[i].id;
// Clean up any existing Drag instances
if (DragDropTable.myDTDrags[id]) {
DragDropTable.myDTDrags[id].unreg();
delete DragDropTable.myDTDrags[id];
}
// Create a Drag instance for each row
myDDRow = new YAHOO.example.DDRows(id);
myDDRow.srcData = DragDropTable.myDataTable.getRecord(id).getData();
myDDRow.onDragDrop = DragDropTable.onDropHandler;
DragDropTable.myDTDrags[id] = myDDRow;
}
}
It seems like if one is listening the other isn't working. I haven't found the syntax for allowing events to continue to bubble or to have multiple subscriptions to onDragDrop. Does anyone have the correct syntax?
Thanks
Josh Robinson