sails js model 'array' type validation and multiple select - express

I'm adding a type validation for my model, example:
selectList: {
type: 'array'
}
The selectList input comes from HTML Form's Multiple Select.
Problem
When user selects zero or one option only, in the case of zero, we get undefined/object type, in case of 1 selection we get 'string' type. Saving it to the selectList will fail.
What is the best solution to handle this issue?
Any ideas? using beforeValidation doesn't sound a good solution to me.

Why not use beforeValidation?
beforeValidation: function(obj, cb) {
if (typeof obj.field === "array") {
cb(null, obj);
}
if (typeof obj.field === "string")
{
var temp = obj.field ;
obj.field = new Array();
obj.field [0] = temp;
}
cb(null, obj);
}

Related

how to get the whole list object variables and arrays without need to get from object child id gundb?

I just notice that object child of object has id but not that I wanted that when I try to get the object variable. I wanted what store in object of object but I found id only?
For example I used scene manage the objects to save and load for easy access.
{
x:0,
y:0,
z:0,
prarms:{height:0,width:0}
}
result from save is when I check the data I found it different.
{
x:0,
y:0,
z:0,
prarms:#randomids
}
I used set and put if the objects matches using the uuid. Need a bit of help on how it get it working. Wanted to get the whole object data but not the gundb object ids.
Manage to get partly working code for set and get data object to work partly. Here simple version how to set.
//console.log("saving object data????");
this.check_gunsceneobj(obj['uuid'],(bfind,id)=>{
//console.log("....CALLS");
var gscene = this.gun.get('scene');
//check child keys var is object to put var
function gunObjectAssign(_gun, _obj){
for(var i in _obj){
if(typeof _obj[i] == 'object'){
console.log(i);
//pathing for object child of object
_gun.path(i).put(_obj[i]);
gunObjectAssign(_gun.path(i),_obj[i]);
}
}
}
if(bfind){
console.log("set object scene[update]");
if(id !=null){
console.log(id);
gscene.path(id).put(obj);
gunObjectAssign(gscene.path(id),obj);
}
}else{
console.log("save object scene[insert]");
//console.log(obj);
gscene.set(obj);
}
console.log("object save?");
});
here the get objects.
function gunObjDataAssign(self,data){
for(var i in data){
if(typeof data[i] === 'object'){
if(data[i] !=null){
var id = data[i]['#'];
data[i] = {}; //clear id hash
self.get(id).val((objdata)=>{
delete objdata._;
data[i] = objdata;
gunObjDataAssign(self,objdata);
});
}
}
}
}
Gun.chain.valueobj = function (cb, opt) {
return this.val(function (val, field) {
if(val !=null){
delete val._;
}
gunObjDataAssign(this,val);
cb.call(this, val, field);
}, opt);
};
Gun.chain.liveobj = function (cb, opt) {
return this.on(function (val, field) {
delete val._;
gunObjDataAssign(this,val);
cb.call(this, val, field);
}, opt);
};
Gun.chain.eachobj = function () {
var each = this.map();
return this.valueobj.apply(each, arguments);
};
Have not fully tested. But it worked party not try detect any update once push to the scene objects.
Used Sample Code from snippets.
If I understand your question correctly... you probably want to use this plugin:
https://github.com/gundb/synchronous
gun.get('player').sync({}, {}, function(player){
// player updated!
console.log("Full object, not just pointers:", player);
})
There is also https://github.com/gundb/onward which gives you the diff and path on the document.
Does this help? Let me know and I'll revise the answer as necessary.

DataTables != search

var table = $('.dataTables-huntQueue').DataTable();
if($('#switch-mine').is(':checked')) {
table.search( 'closed' ).draw();
} else {
table.search( '' ).draw();
}
The above works great when all I'm looking for is the 'closed' value. But what I really want is anything that is NOT closed. Is there a ! operator here that I'm missing?
You can use a regular expression :
table.search('^((?!(closed)).)*$', true, false, true).draw();
The meaning of the params is - see the documentation for search() :
rows which not have columns containing "closed"
It is a regular expression
no "smart" filtering, in this case it doesnt seem to matter though
case insensitive
The downside by using a regex through the API is that you will get an ugly meaningless ^((?!(closed)).)*$ value in the search / filter box. Instead you can make a custom filter that does exactly the same :
function notSearch(notString) {
notString = notString.toLowerCase();
$.fn.dataTable.ext.search.push(
function(settings, data, dataIndex) {
for (var i=0;i<data.length;i++) {
if (data[i].toLowerCase().indexOf(notString)>-1) return false;
}
return true;
}
)
table.draw();
$.fn.dataTable.ext.search.pop();
}
Then call it by
notSearch('closed');
You can even register the above custom filter so it appears as part of the native API :
jQuery.fn.dataTable.Api.register('notSearch()', function(notString) {
notString = notString.toLowerCase();
$.fn.dataTable.ext.search.push(
function(settings, data, dataIndex) {
for (var i=0;i<data.length;i++) {
if (data[i].toLowerCase().indexOf(notString)>-1) return false;
}
return true;
}
)
table.draw();
$.fn.dataTable.ext.search.pop();
})
table.rows().notSearch('closed');

Express JS what is the correct way to inject non-field property into Mongoose model before return it to client

Using Mongoose model method findOne, I receive a model. Now I want to custom that model before sending it to client, augmenting several attributes into that model.
However, the only way I found for the moment is to turn that model into plain object and augment that object.
I don't know is there any better way doing it?
Here is my lengthy code for that simple purpose:
Topic.find({}).exec(function (err, topics) {
var i, topic_obj, topic_obj_list;
topic_obj_list = [];
if (err) { return next(err); }
for (i = 0; i < topics.length; i++) {
topic_obj = topics[i].toObject();
if (req.user.is_following) {
topic_obj.is_following = true;
} else {
topic_obj.is_following = false;
}
topic_obj_list.push(topic_obj);
}
return res.json(200, topic_obj_list);
});
P/S: I already tried simple solution like: topics[i].is_following = true, bit it didn't work.
You can shorten it to something like this:
Topic.find({}).exec(function (err, topics) {
if (err) { return next(err); }
return res.json(topics.map(function(topic) {
return topic.set(
'is_following',
req.user.is_following ? true : false,
{ strict : false }
);
}));
});
Explanation:
topics.map runs a function on each item of the topics array; the value that is returned from the function ends up in the result returned by map;
with topic.set(FIELD, VALUE, [{ strict : false }]) you can add/overwrite fields of a Mongoose document; when strict is false, the field doesn't have to exist in the schema;

Is it possible to filter data in a dgrid like you can in a datagrid? If so, how?

I'm relatively new to dojo and have seen how datagrid offers a dynamic filtering capability that reduces the visible rows based on what you type into a filter text input. I have not found any examples of how to do it with the dgrid. If it can be done, please provide an example or point me to a resource that offers a tutorial or example. Thanks!
Yes, it is possible. Use dgrid/OnDemandGrid and define query function that will return true or false based on your logic for each row in dojo/store powering the grid.
I prepared an example to play with at jsFiddle: http://jsfiddle.net/phusick/7gnFd/, so I do not have to explain too much:
The Query Function:
var filterQuery = function(item, index, items) {
var filterString = filter ? filter.get("value") + "" : "";
// early exists
if (filterString.length < 2) return true;
if (!item.Name) return false;
// compare
var name = (item.Name + "").toLowerCase();
if (~name.indexOf(filterString.toLowerCase())) { return true;}
return false;
};
The Grid:
var grid = new Grid({
store: store,
query: filterQuery, // <== the query function for filtering
columns: {
Name: "Name",
Year: "Year",
Artist: "Artist",
Album: "Album",
Genre: "Genre"
}
}, "grid");
I know this isn't the answer to the question asked, and the answer provided is masterful and we use it quite a bit.
However, this functionality doesn't seem to work well at all if you're using a TreeGrid (columns with the "dgrid/tree" plugin). I've written some code to simulate the same behavior as the accepted answer with a tree grid. It's basically just looping through the items in the store and hiding any row elements that don't match whatever condition you set forth. Thought I would share it in case it helps anybody. It's rather ugly and I'm sure it can be improved upon, but it works.
It basically uses the same concept as phusick's answer. You need to watch a value on a TextBox, but instead of refreshing the grid you have it call a function:
textBox.watch("value", lang.hitch(this, function() {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
};
timeoutId = setTimeout(lang.hitch(this, function() {
this.filterGridByName(textBox.get('value'), myGrid);
}, 300));
}));
And here's the function:
filterGridByName: function(name, grid){
try {
for (var j in grid.store.data){
var dataItem = grid.store.data[j];
var childrenLength = dataItem.children.length;
var childrenHiddenCount = 0;
var parentRow = grid.row(dataItem.id);
for (var k in dataItem.children){
var row = grid.row(dataItem.children[k].id);
var found = false;
if (dataItem.children[k].name.toLowerCase().indexOf(name.toLowerCase()) != -1){
found = true;
}
if (found){
if (row.element){
domStyle.set(row.element, "display", "block");
}
if (parentRow.element){
domStyle.set(parentRow.element, "display", "block");
}
} else {
childrenHiddenCount++;
// programmatically uncheck any hidden item so hidden items
for (var m in grid.dirty){
if (m === dataItem.children[k].id && grid.dirty[m].selected){
grid.dirty[m].selected = false;
}
}
if (row.element){
domStyle.set(row.element, "display", "none");
}
}
}
// if all of the children were hidden, hide the parent too
if (childrenLength === childrenHiddenCount){
domStyle.set(parentRow.element, "display", "none");
}
}
} catch (err){
console.info("error: ", err);
}
}

In an ExtJS Grid, how do I get access to the data store fields that are part of the sort set

How do I get access to the columns/datastore fields that are part of the sort set.
I am looking to modify the a grid's sort parameters for remote sorting. I need the remote sort param's sort key to match the column's field's mapping property. I need these things to happen though the normal 'column header click sorts the data' functionality.
Remote sorting and field mapping (ExtJS 4.1)
This functionality seems not to be implemented in ExtJS. Here is a solution using the encodeSorters function provided since ExtJS 4. Accessing fields map throught the model's prototype is a bit dirty but it does the job :
var store = Ext.create('Ext.data.Store', {
...,
proxy: {
...,
encodeSorters: function (sorters) {
var model = store.proxy.model,
map = model.prototype.fields.map;
return Ext.encode(Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
}));
}
}
});
However, it would be more relevant to override the original method :
Ext.data.proxy.Server.override({
encodeSorters: function(sorters) {
var min, map = this.model.prototype.fields.map;
min = Ext.Array.map(sorters, function (sorter) {
return {
property : map[sorter.property].mapping || sorter.property,
direction: sorter.direction
};
});
return this.applyEncoding(min);
}
});
Assuming you are using simpleSortMode, you could do something like this in your store.
listeners: {
beforeload: function( store, operation, eOpts ) {
if (store.sorters.length > 0) {
var sorter = store.sorters.getAt(0),
dir = sorter.direction,
prop = sorter.property,
fields = store.model.getFields(),
i,
applyProp = prop;
for (i = 0; i < fields.length; i++) {
if (fields[i].name == prop) {
applyProp = fields[i].mapping || prop;
break;
}
}
//clearing the sorters since the simpleSortMode is true so there will be only one sorter
store.sorters.clear();
store.sorters.insert(0, applyProp, new Ext.util.Sorter({
property : applyProp,
direction: dir
}));
}
}
},