Enforce unique key values in ExtJs 4 grids - javascript

I'm designing a grid in ExtJs 4 that will represent a Map data structure. I have a custom cell editor for the key column in the grid. I want to enforce the fact that the key must be unique among all keys. How do I go about doing this?
At the moment I'm trying to set up a special textfield editor with a custom validator that checks if the user-submitted key value is unique by comparing it to the dataStore's values. Unfortunately, this runs into the issue that the dataStore does not know what is the "current" record and so does not know which record to exclude when checking for duplicates.
^Confusing, right? That's why I think I'm doing it wrong.

It's a very good question, and I ended up doing pretty much exactly what you're doing. In order to handle current record so I can exclude it from the lookup I added something like that to the vtype validation function:
unique: function (val, field) {
// If field has not been changed - don't care about anything else
if (field.originalValue === undefined || val === field.originalValue) {
// _trace('unique - original value has not changed');
return true;
}
if (!field.isDirty()) {
// _trace('unique - field is not dirty');
return true;
}
// Check you store here...
},
uniqueText: 'Duplicate'
One more note - if you will try to use same validator in the dialogs (as oppose to grid roweditor) - you will need to add more checks because originalValue will not be properly set always (at least I had to do this in 4.0.7 in my application).

Related

How to access an entered Interactive Grid column value in a Javascript dynamic action on the Change event in order to ensure uniqueness

I am trying to prevent duplicate items from being entered in an Interactive Grid in Oracle Apex 20.2. I do get a unique constraint error when this happens, but this is for a barcode scanning stock control app and the unique constraint error only happens when saving after scanning a room with lots of objects. It is then very difficult to find the duplicate field. You also cannot use sort, since that wants to refresh the page and looses all your scanned items. I cannot presort because I want the last scanned item on top.
I was able to add Javascript on page load that creates an array with all the barcodes. I then check this array when scanning and do not add new Interactive Grid rows when a duplicate barcode is going to be added to the array.
In addition to this I need to add the same for when an Interactive Grid row is manually entered. For this I wanted to add a Javascript dynamic action on the barcode column in the Interactive Grid, in order to once again check the global array for uniqueness. However I have several issues: I cannot figure out how the get the entered barcode value in the change dynamic action Javascript, sometimes it shows the previous changed value (might be this bug although I am in 20.2) and the Change event also seems to fire twice when hitting enter after entering a value (once for the new row (this time my code works unlike when hitting Tab) and once for the next row below). The last one seems bad, since then it will try to check existing values (the next row) and give errors that should not happen; however I do not see a more appropriate event like On Row Submit. Not sure if there is a way to check whether the value changed on the Change event.
The code I currently have I got from here. I am assuming this means Oracle Apex does not have a standard way of getting an Interactive Grid column value in a Javascript dynamic action. Not sure if this has changed in 20.2 or 21. The code I have is:
console.log($(this.triggeringElement));
var grid = apex.region('LINES').widget().interactiveGrid('getViews', 'grid');
var model = grid.model;
var selectedRow = grid.view$.grid('getSelection');
var id = $(selectedRow[0][0]).data('id');
var record = model.getRecord(id);
let bcode = model.getValue(record, 'BARCODE');
console.log(id);
console.log(record);
console.log($(selectedRow[0][0]));
console.log(bcode);
if(barcodes.includes(bcode)) {
apex.message.showErrors([{
type: "error",
location: "page",
message: "The entered barcode is already in the list.",
unsafe: false
}]);
}
When I console.log(record) I can see values that I enter into the barcode column, but I do not know how to walk the object tree in order to retrieve the value out of the record. I do not understand the object it shows me in the console log. It does not seem to correlate with the dot access traversals that others are doing in the above code. I can see the record array at the top, but for that the barcode column shows the previous value; below that it does however show the newly entered value as the third (2) index, but I do not know how to write Javascript to access that.
If I can access the previous and new value from the record object I could check for changes and also compare the new value against the global array. How do I access these values in the record object or is there a better way of achieving my goal? bcode prints the previous value, so I guess I already have that if that is not a bug.

Allow a specific nested value to be updated in Firestore

I need to give anonymous users the ability to update a specific value inside a nested architecture without giving permission on the rest of the document.
events is a top level collection and I update my document like so
update(`events/${event.id}`, {
[`boardgames.${boardgameId}.votes.${uid}`]: true,
})
I have tried this solution
allow update: if ((request.writeFields.size() == 1) && ('boardgames' in request.writeFields));
as mentioned here but it fails (both halves fails independently too).
What am I missing? Am I not updating only one field when 'going inside' a nested object?
It would be super helpful to be able to console.log the request and the request.writeFields.
Note that ideally I would like to only allow modification on the deepest property, the current user's uid inside the votes.
Actually, request.writeFields captures the full path of the modified fields, so in your case it will be equal to boardgames.${boardgameId}.votes.${uid}.
You could use a regex with String.matches
allow update: if request.auth.uid != null
&& request.writeFields.size() == 1
&& request.writeFields[0].matches("boardgames\.[^.]{5,25}\.votes\." + request.auth.uid)
Careful: request.writeFields is deprecated but unfortunately there is no good replacement for your problem

Slickgrid header row filtering empty cells not working in example

I was looking into this example and saw that filtering does not happen when searching for empty cells. This means I typed any string in the filterbox and then removing the string. However, when debugging it locally and making some cells empty, I saw that dataview.refresh() is called upon an empty input, the grid just doesn't display the empty cells.
In my application I have a use case where one might want to search for all cells that have no content, so my question is, is this something that can be changed, or is it baked deeply under the Slickgrid hood?
I can understand the use case in the linked example, as it already loads the filters on page load, but in my application the filter is only applied after a confirmation button click.
Thanks for your help.
This is all completely configurable. In the example you link,
dataView.setFilter(filter);
sets up the filtering, and passes the filter function
function filter(item) {
for (var columnId in columnFilters) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
var c = grid.getColumns()[grid.getColumnIndex(columnId)];
if (item[c.field] != columnFilters[columnId]) {
return false;
}
}
}
return true;
}
To make the changes you suggest, simply edit the columnFilters[columnId] !== "" bit. You'll need to work out some other way of telling whether to apply the filter or not, rather than an empty string.

Using a dynamic variable to access another variable's value in Meteor?

So I'm trying to make my code more modular for sanity purposes (and because it seems more efficient than writing the same code five+ different ways).
However, I'm running against a wall on this one as my JavaScript knowledge is apparently lacking.
I've got a method call for buying various unit types. I want to check that the player has enough of a particular type of unit citizens or soldiers before training a more advanced type citizen.workers or soldier.specific. Incrementing the more advanced type isn't a problem I'm addressing yet; I'm simply trying to determine if the base unit is present in a minimum quantity.
What I'm currently using is not working. The type variable is not evaluating but is rather going through as "type" when I want it to default as "citizens". I'm using the variable in 2 places, the if statement for evaluation purposes and in the DB update to reduce the number of that particular field.
Current code:
'buy': function(cost, number, type) {
type = type || "citizens";
var currentUser = Meteor.user();
var player = Players.findOne({createdBy: currentUser._id});
if(player.credits >= cost && cost > 0 && player.type >= number && number > 0) {
Players.update({createdBy: currentUser._id}, {$inc: {'credits': (0-cost), type: (0-number)}});
return true;
}
return false;
},
Searched all over but was not finding what I was looking for or even something I could start with and begin to apply it to what I needed. Any help would be great.
Edit: Yes I realized I was using a default value incorrectly for javascript. I've modified that in my code. The computed value David Weldon answered with was what I was going after more specifically.
Change your code in the following ways:
player[type] >= number
and
{$inc: {'credits': (0-cost), [type]: (0-number)}}
The latter is an example of a computed property key which is new in es6.
Also see the 'Variables as Keys' section of common mistakes.

Dgrid : How to save and persist column order?

I'm using dgrid with the column reorder extension. I have two questions here -
I see that after reordering columns, the columns are present in the new order in the subRows attrinute of grid (note that I'm not referring to subRow here). Is that the best way to get the column order or are there any alternate/better ways to do it?
I understand that I will need to take care of saving the column order (or any other property for that matter) and restoring it. When I'm creating the grid with a saved order, what is the best way to do it? Should I create the columns in the saved order or can I create them in the standard order and then re-order them as per my saved order? If the latter is possible, how do I do it?
Thanks,
Yes, subRows is likely the most consistent way to get the column order.
Regarding saving/restoring, I could fathom doing something like the following. Note that for simplicity's sake, I'm making some assumptions here:
You only have a single sub-row (the same approach could be used for multiple, I figure, but you'd need outer loops)
Each column references a unique field
You are targeting only ES5+ environments (since I use ES5 Array methods below)
When saving the sub-rows, save just the field that each column references (which will make it trivial to serialize):
var persistedSubRow = grid.subRows[0].map(function (column) {
return column.field;
}
Then, when creating the grid, have an object hash of your columns in the default order (which you can use to set columns if there are no persisted settings), but if persisted settings exist, use that to determine the order by mapping it back against the hash:
var columns = {
field1: ...,
field2: ...,
...
}
if (persistedSubRow) {
persistedSubRow = persistedColumns.map(function (field) {
var column = columns[field];
// Normally when an object hash is specified for columns,
// field is autodetected from the key. Converting to array will
// lose that, so set it within the object.
column.field = field;
return column;
});
}
var grid = new Grid({
// grid.columns accepts either an object or array as input
columns: persistedSubRow || columns,
...
});
Let me know if you run into trouble; I'm shooting from the hip here, and haven't tested the above.

Categories