Is there a possibility to "override" the equality check of the generated property setters?
I like to have a (integer) property that can distinguish 0 (zero) from -0 (negative zero).
For example this:
qx.Class.define("io.Dummy",
{
extend : qx.core.Object,
properties :
{
value : {
check : "Integer",
nullable : true,
init : null,
event : "changeValue"
}
}
});
so that following code will fire 3 events (instead of only 1):
var dummy = new infodesk.Dummy();
dummy.addListener("changeValue", function (e) {
this.info("changed!");
}, this);
dummy.setValue(-0); // <= changed!
dummy.setValue(-0);
dummy.setValue(+0); // <= changed!
dummy.setValue(+0);
dummy.setValue(-0); // <= changed!
dummy.setValue(-0);
When I "patch" the equality-checks in the framework (qx.core.Property's __emitXxx methods) by replacing code like "if (a===b)" with "if(Object.is(a,b))"[1] it works,
...but it would be nice if there's a nicer -more clean- way of doing this.
Maybe this is a feature request?
For a property definition attribute like "compare" (Function) or "altCheck" (Boolean)?
properties :
{
value : {
check : "Integer",
nullable : true,
init : null,
event : "changeValue",
altCheck : true // 'alternative check enabled'
// rsp.:
compare : function (a, b) { return Object.is(a, b); }
}
}
[1] ECMA-Script 6
As qooxdoo does not offer the functionality of defining a custom value comparer, please open an issue at the github issue tracker at https://github.com/qooxdoo/qooxdoo/ .
I think the idea of having a compare attribute which allows to define a custom comparer is a good idea. If the compare attribute is omitted, the default comparer should be used.
The best way of getting the functionality you need into qooxdoo is to create a pull request which implements the feature, accompanied by unit tests.
I copied the code you mentioned above and found that "changeValue" event happened only once, not 3 times! I use Qooxdoo Playground v5.0.1, Firefox 47.0, Win7.
What's wrong?
You can solve the problem by using the transform key of qooxdoo property, saving the data as string instead of an integer.
Related
When I update a model, waterlock .update() always return an array of objects, even if I set on criteria a primaryKey.
on my code
Ad.update({ id: req.param('id') }, {
// desired attributed to be updated
}).exec(function(err, updatedRecord) {
// updatedRecord is always an array of objects
});
And in order to use the updatedRecord, I have to point out to 0 index like updatedRecord[0] which is something I consider not very clean. According to docs update() in sails, this is a common escenario.
Knowing that, I have 2 questions:
Wouldn't be better that when you find one model return just a updated object for that model, not an array?
If that is a convention, how could be overrided this function in order to return just an object instead of an array when .update() have only affected one record?
it is a convention that it will update all the records that matches the find criteria, but as you are probably using a unique validation on model, it will probably return an array of 1 or 0. You need to do it on hand.
You can override methods in model, by implementing a method with same name as waterline default. But as you will need to completely rewrite the code, it is not viable. Neither changing waterline underlying code.
A solution will be creating a new function on your Ad model:
module.exports = {
attributes: {
adid: {
unique: true,
required: true
},
updateMe: {
}
},
updateOne: function(adid, newUpdateMe, cb){
Ad.update({ id: req.param('id') }, {
// desired attributed to be updated
}).exec(function(err, updatedRecord) {
// updatedRecord is always an array of objects
if (updatedRecord.length == 1){
return cb(null, updatedRecord[0]);
}
return cb(null, {}); //also can error if not found.
});
}
};
Also. Avoid using id as an model attribute (use other name), as some databases like mongodb already add this attribute as default and may cause conflicts with your model.
I dont think its possible with waterline. Its because update method is a generalized one, passing a primary key in where condition is always not the case.
I have an input field that is supposed to contain numbers.
It is bound to an object property.
I want input entered as 4,5 to automatically get converted to 4.5 in both model and view.
HTML:
<input data-ng-model="productContent(product.Id).Org" value="{{productContent(product.Id).Org | replaceComma}}" />
Control:
$scope.productContent = function (prodId) {
var content = $.grep($scope.productsContent, function (el) { return el.ProdId === prodId });
return content[0];}
Filter:
app.filter('replaceComma', function () {
return function (val) {
return (typeof val) == "string" ? val.toString().trim().replace(",", ".") : val
};
});
Result:
When I enter a number, at first the model (productContent) retrieves the correct object. Then the filter code is called and returns a correctly converted string. I would expect both the model and view to be updated to the filtered value, but both are updated with the unfiltered value. What am I doing wrong?
I have faced the same problem in the past but instead of creating my own filter, I took a different path and found something ready to use instead.
angular-input-masks by assisrafael one of my favourite angular extensions for this purpose:
https://github.com/assisrafael/angular-input-masks
Examples:
http://assisrafael.github.io/angular-input-masks/
Since the author has written the documentation, I don't want to get extensive on it and be outdated in the future. As a quick reference, look for ui-number-mask.
Maybe this is not a direct answer to your question, since it's not replacing commas with periods, but making you type the decimals instead.
On a side note, you can suppress the thousands separators with ui-hide-group-sep
I hope that's helpful, otherwise leave a comment and I'll be happy to continue to assist you!
-Helvio
http://documentcloud.github.io/backbone/#Model-id indicates that the id property of a model is special because if my_model.set("id", <new_id>) is called, my_model.id will have that new value. This property is not commutative, however. Calling my_model.id = 4 followed by my_model.get("id") will not result in 4.
Is there a way to have my_model.id=4 set the value of my_model.attributes.id so that my_model.get("id") will result in 4?
To achieve what you want, you can override the get method of Backbone.Model, but that is not a very good proposition cause there is a reason why model id and id property of attribute are separated from each other, id of model is something local to backbone and id property of the attribute is something that might be used by the remote servers when you sync your model.
So in usual cases, overriding the get function of Model can cause trouble in future.
You can achieves what you want like this :
Backbone.Model.prototype.get = function(attr) {
if (attr == 'id' && this.attributes[attr] != this.id) {
this.attributes[attr] = this.id;
}
return this.attributes[attr];
};
I'm using a custom validator on my combobox's:
function(v) {
console.log(v === 'some value I know for SURE is in the store'); // (1)
var index = this.getStore().findExact(this.displayField, v);
return (index!==-1) ? true : 'Invalid selection';
}
Basically admits the same set as forceSelection but allows the user to type arbitrary text to attempt to auto-complete.
However; I'm having really odd results with findExact(). For example, if the combobox's value is currently valid, and a user does a space + backspace, the validator will fail, even though the output of (1) is true.
Any ideas what is causing the problem? The end-experience is currently very buggy-feeling..
When you type additional space, store is filtered. After you press backspace, and validator is fired, store is still empty.
If you have local store, then you could validate combo with some delay after each change. Example:
listeners: {
change: function() {
this.validate();
},
delay: 100
}
That should be enough.
On the other hand if you have remote store, try something like this:
validator: function(v) {
var store = this.getStore(),
index = store.findExact(this.displayField, v);
if (index === -1 && store.isLoading()) {
store.on('load', function() {
this.validate();
}, this, { single: true, delay: 100 });
}
return (index !== -1) ? true : 'Invalid selection';
}
I had a similar issue and found this entry. My problem was, that I reused the same store instance across multiple ComboBoxes. After giving each ComboBox an own store with cloned data, everything was fine.
See also:
https://www.sencha.com/forum/showthread.php?305182-ComboBox-forceSelection-clears-input&p=1127218&viewfull=1#post1127218
I just spent a few days on this issue and found a really great solution (by accident, really). You can - as the accepted answer suggests - utilize the provided validator function; however, from my understanding, there is a much simpler solution than the accepted answer provides: evaluating whether or not the user-provided input equates to a value in the store (which is the underlying question in the original post).
The advantage of thinking about the input in this way is that it enables us to handle the use case of an invalid value entered by the user (validated; no value) and - after the field loses focus - Ext JS sets the field back to its previous value (which remembers its store value).
This is an entirely different route than your thinking, but it should work, especially as .validate() runs regardless of whether you provide an implementation of the validator procedure:
validator : function(someParam) {
if(this.value === null) {
return "error message"; //falsy
} else {
return true;
}
}
If you enable forceSelection, the above works, very well, and gets rid of the buggy feeling. This allows you to rely on the .validate to do its magic elsewhere (notice I don't even call it; read the doc. to figure out when its called in relationship to validator) and not have to worry about what the user correctly explains in the accepted answer.
We were having trouble with forceSelection clearing user text before they were finished typing. We seemed to get what we needed by setting forceSelection false and just checking that they selected something.
validator: function(v) {
if (this.getSelection() === null) {
return 'invalid text';
}else{
return true;
}
}
In my Backbone app, on my collection I have numerous sorting methods, when rendering the views based on the collection I am currently using a global var set via the route (I do it with a global as other actions add to the collection and I want the last ordering to be used). For example
routes : {
"" : "index",
'/ordering/:order' : 'ordering'
},
ordering : function(theorder) {
ordering = theorder;
listView.render();
},
then in my view
if (typeof ordering === 'undefined') {
d = this.collection.ordered();
}
else if(ordering == 'owners') {
d = this.collection.owners();
}
_.each(d, function(model){
model.set({request : self.model.toJSON()});
var view = new TB_BB.OfferItemView({model : model});
els.push(view.render().el);
});
Where ordered and owners are the 2 ordering methods.
So my first question is, based on routes could someone advice a better way of implementing above? This view gets rendered in multiple places hence me using a global rather than passing a ordered var to the method?
Second question is - I would like to also add some filtering, so lets say I want to sort by 'price' but also do some filtering (lets say by multiple categories id). How could I add a flexible 'route' to deal with filtering.
I guess I could do
routes : {
"" : "index",
'/ordering/:order/:filter1/:filter2' : 'ordering'
},
So the filter1 and filter2 would be the subsequent filtering, but if the filters could be 0 or 100 this will not work. Could anyone offer a solution?
Well, first you should be using Backbone's built-in ability to auto-sort collections. You can take advantage of this by defining a comparator function on your collection. This gives you all kinds of wins right out of the box — for example, the collection will re-sort itself every time you add or remove something from it, based on your comparator. If you want to define multiple sort functions, just define them all as functions and then update comparator when you need to. Then you can ditch that ugly global var.
For your second question, I'm not totally sure what you mean by "if the filters could be 0 or 100 this will not work." If you mean that you'll run into trouble if you don't specifiy all of the filters, then that's true. But you can use a wildcard to fix that. Here's what that might look like:
// your routes look like this:
routes : {
'/ordering/:order/filters/*filters' : 'ordering' // your routes will look like: /ordering/price/filters/filter_one/filter_two/filter_three
},
ordering: function (order, filters) {
filters = filters.split('/'); // creates an array of filters: ['filter_one', 'filter_two', 'filter_three']
listView.render(filters); // pass your filters to the view
}
// listView.render() looks like this:
render: function(filters) {
collection = this.collection;
_.each(filters, function (filter) {
collection = collection.filter(function () {
// your actual filtering code based on what the filter is
});
});
}