How to make render() work independently when user- or application-filtering?
How to make render() work independently when user- or application-filtering?
I just fell into a situation where the currently available set of values for type
seems not enough to work as simply as it'd be possible.
Here is a pretty simple use case that illustrates the problem.
Having a column (say "allowed") containing a boolean value, which contains "0" or "1" (comes from a DB content).
Obviously it needs to be more friendly displayed so we'll do something like this:
var table = $('#example').dataTable({
columnDefs: [{
data: 'allowed',
render: function (data, type, row, meta) {
return data == '1' ? 'yes : 'no';
}
}]
});
Since we didn't do anything depending on type
above, the user can type "yes" or "no" in the dedicated filter area to display only the allowed (respectively not-allowed) rows .
In the other hand, if for some reason the application must directly filter rows by itself, we can do for instance:
table.columns(<col index>).search('yes').draw;
So far so good.
Now if the application works in a multilingual context where a localize()
function is available, the first scriptlet above becomes:
var table = $('#example').dataTable({
columnDefs: [{
data: 'allowed',
render: function (data, type, row, meta) {
return localize(data == '1' ? 'yes : 'no');
}
}]
});
Then user filtering keeps working fine, wether using "yes|no", "si|no", "oui|non", and so on.
But... now application filtering works only when the current language is English!
So one immediate obvious solution is to also change the second scriptlet accordingly:
table.columns(<col index>).search(localize('yes')).draw;
Sure then it works fine anew, but here is what I wanted to expose: isn'it too bad to have to use localize()
again, while in this case a more immediate and elegant method would be to directly work with the original data value "0|1":
table.columns(<col index>).search('1').draw;
For this to work, it'd suffice to make render()
work depending on its type
argument.
But it's not currently possible: the "filter" type
is the one used by DataTables both when responding to user-filtering and to column.search()
.
(BTW I guess that maybe user-filtering just uses column.search()
...)
Here we retrieve what the doc says about the filter|search ambiguity.
So it'll be great if it could be uncoupled (may be by adding a new type
value "search"?).
Thanks for your attention.
Answers
Erratum
Just under the first scriptlet in the previous post, please read
type
above instead oftype
below.Sorry.
edited by Allan - I've modified your post above to reflect that correction.
I don't quite understand that point I'm afraid. The filtering should be language independent - it will be based on whatever is in the table (or what returned by the renderer for a
filter
type). Can you show me an example of that problem?Regarding using a search for
0
and1
as well asyes
andno
(or their translations), I would suggest something like:or similar. i.e. have both the data values you want to be filtered on available in the search string.
Allan
Hi Allan, thanks for your answer.
Aside comment: thanks for correcting my initial post. I hadn't found a way for doing it by myself once posted: did I missed something?
Furthermore I lately noticed that I let another error: in my scriptlets I always forgot parenthesis in
.draw()
.Now regarding my question, I'm a bit disconcerted by your answer, so I'm afraid I didn't clearly explained.
Unless I misinterpret what is "that point" above, what I meant with "now application filtering works only when the current language is English!" is: when
render()
has been modified to return a localized value, then.search('yes')
will not match, for instance, the spanish versionsi
.In my mind the use case I exposed is precisely the example of the problem.
Said in other words, it is: we can't make a
render()
function return different results whether it's invoked in.search()
or simple user-filtering process, because both use the sametype
value "filter".Here again, I see the need of a distinction depending on what is being processed:
.search()
(remember it's ran by the application itself), yes it absolutely should be language independent (at least ideally), and so will be based on whatever is in the table (in this case, the boolean value0
|1
).Another thing must be pointed out: while
.search()
can be (and here, is) launched in the context of a unique column so it's not ambiguous, by design user-filtering always works on any visible column.So in fact their intent is fundamentally different (even if they be common in some cases).
But, and here is the problem at my eyes, this difference can't be well-preserved at the time
render()
is invoked, because the data it returns can't be maked different.With my current workaround:
.search(localize('yes'))
ensures a correct (non-ambiguous) filtering since the value returned byrender()
can't contain anything else than the localized value ofyes
orno
.In the other hand, no offense but I find that your suggestion to use
data + ' ' + localize(data)
as returned value fromrender()
is not a better one:.search('1')
for a correct result when application-filtering0
or1
which likely may easily happen with columns containing integers.Finally it's why I imagined it could be of interest to have a new possible value "search" for
type
, that would be used byrender()
when.search()
is processed, so allowing to work like this:(here I intentionally write more code than needed, for the sake of clarity)
which in turn allows application-filtering to remain the most simple, and language independent:
Hoping to have been more clear... and not too annoying!
Thanks for your attention.
Fred
Hi Fred,
Thanks for your reply. Regarding editing posts - you can do so for 15 minutes after the post. After that you'd need to post a correction as you did.
Regarding the problem - I've created this little example: http://live.datatables.net/joyinohe/1/edit .
It uses a trivial little
localize
function (you can change the name of the variable it uses to change the "dictionary").It seems to work as I would expect - you can filter on Si or No as it is setup. You cannot search on the office location ("London" for example).
Can you modify that example, or link me to a page, that shows the issue you describe so I can more fully understand it please?
Regards,
Allan
Hi Allan, thanks for your effort.
Here is a modified version of your example: http://live.datatables.net/joyinohe/2/.
_BTW sorry if it doesn't allow edition (I just noticed that "/edit" is omitted in the url above): I'm familiar with jsfiddle and stackOverflow contexts, and was a bit surprised with the somewhat different behaviour of joyinohe.
Particularly I'm not quite sure it auto-saved my version! Let me know.
I totally agree, and there is no problem till here.
So in my modified version I added what I previously named application-filtering, which uses
search()
, and should ideally be language independent, as we both said: hence it should be able to retrieve "London".And you can see that it doesn't, even if localizing only when
type === 'filter'
:.search()
always gets the localized version returned byrender()
.It's why I talk about an hypothetical "search" value for
type
, which might be the onerender()
gets passed when.search()
ing, so we could return the original data in this case.I realize that till now I couldn't clearly transmit my point of view, probably due to my poor English (as a French man I struggle to express myself in that language, and I'm never sure I succeeded).
So, sorry to take your time, and thanks for your patience.
Fred
Hi Fred,
Your English is excellent. Far better than my embarrassing school boy French...! And yes, JSBin is a little different in how it handles URLs - it does auto save.
I think part of the issue here is that the
type === 'filter'
is actually legacy. For backwards compatibility it didn't change it to betype === 'search'
, but really, that is what it should be called (since the term "search" is used else where in the API for searching the table)!If you want the search term to include both the localised and the original data, you can do something like:
return localized + ' '+ data;
: http://live.datatables.net/joyinohe/3/editIf we introduce
search
in addition tofilter
, it would be another search API that would be required, and I think that would get really confusing.Regards,
Allan
Hi Allan,
I persist to think that, despite of your kind words about my English, till now I failed to really and clearly transmit what I'm looking for.
I'll try again one more time, but please don't feel too annoyed by my insistance!
It's notably by reading this that I think I didn't clearly explain my goal.
It seems to me (maybe naively) that for what I have in mind it'd be sufficient to slightly change the way
render()
is internally invoked.Remember that my fundamental intent is only to be able to work with
render()
in a way that allows to detect if we're in the context of user-filtering (i.e. when the user typed something in the dedicated "filter" area), as opposed to any otherrender()
invocation.If I correctly understand what you said about the trouble with search|filter terms, it means (and comes from the fact) that in fact user-filtering process internally uses
.search()
, which in turn invokesrender()
always with the sametype = 'filter'
, so we can't detect if we're in the user-filtering process or not.So let's give up my previous suggestion of introducing a supplemental
type = 'search'
.And here is the alternative solution I now imagine: would'nt it possible to introduce a context variable (say for instance
searchContext
), which might be:undefined
or'unknown'
at init time'user'
at the beginning of the user-filtering process (and reset when it's finished)meta
object transmitted torender()
I think that it's really only a slight change, and without any compatibility issue.
Then inside the code of a
render()
instance we could know when it comes from the user action, and return a localized value, while returning the raw value in other occurrences.Something like this (again, more code than needed, to be totally clear):
Last point, and sorry to insist on this: using
return localized + ' ' + data;
doesn't produce exactly the hoped result.Indeed it permits to retain the raw values (and so be language independent when we want it), but it does this also when user-filtering, so it makes the set of retained values wider than those displayed, which seems rather strange against what may be expected in this situation.
Again, sorry for my persistance, and thanks for your attention.
Fred
Thanks for following up on this - its fantastic to have a conversation about enhancements to DataTables!
My main issue with what you propose is that the
search()
andcolumn().search()
methods should use thefilter
orthogonal data type. Thesearch()
method calls exactly the same code as the search box at the top of the table.The issue is compounded further by
column().search()
since DataTables itself doesn't provide inputs for column search. If you look at this example you will be able to see that it usescolumn().search()
. What you propose would break that if renderers were used to display something different in the table.In essence there is no knowledge of if a search is triggered by the end user or not, and I think it would be very difficult to determine that. It would also require layering of search, since you would want an API search to be combined with a user search.
I completely agree that DataTables does need to significantly improve its filtering, but I'm not sure that this is the right way to do it I'm afraid. My current thought to allow access to the raw data programmatically is to allow
search()
to accept a function that can be used to search the data. How to clear that, and how to layer it is currently an open question though.Allan
Hi Allan,
I really appreciate your courtesy effort.
Regarding the rest I must confess I couldn't fully understand your argumentation, since I never dived deep enough in the API.
Nevertheless there is something I precisely realized when looking at the example you pointed out: it's that your understanding of my idea is a bit disturbed by, again, my lack of precision till now.
I guess you probably imagined that inputs such those of this example also belong to what I called "user-filtering", hence your comment:
But it's not the case! For me, "user-filtering" (sure it's appears badly named now) addresses only the data typed in the dedicated "Filter" area which is part of the core DataTables layout.
The reason of the difference at my eyes is: this area is the only one the developer can't control, while he has hand on the inputs of the example since they're his own creation, and so he can take any needed measures to effectively control all that happen about them.
So as I persisted to imagine that things could work more simply than you fear (and because I'm somewhat obstinate ), I did some partial tests in order to prove that we could in fact determine that user-filtering has been triggered.
And the funny thing is that they lead me to a complete solution working like I want without needing a DataTables enhancement!
In a few words, it works like this (not fully tested yet, but seems that it should actualy succeed):
userFiltering
, initially remains undefineddraw
event touserFiltering = undefined;
, bindkeyup
event on the dedicated "Filter" area touserFiltering = 'user';
render()
as previously exposedSo I can assert I'll not annoy you any longer with this!
Again, thanks for have been so patient.
Fred
If you use
search()
to set a search value, you'll see that is also sets the value in theinput
element you call "user-filtering": http://live.datatables.net/zaqufowu/1/edit .The
input
element andsearch()
do the same thing - indeed theinput
element is basically:That's why I say we can't know if the input is user filtered or not. Its possible to say that if you don't use
search()
(which might be true in a specific case, but isn't always true). Its even worse when usingcolumn().search()
since DataTables doesn't provide any input elements for that - you have to use `-api column().search().Great to hear that you've got a work around though!
Allan
Hi Allan,
Thanks for this added information.
Sure I was pretty surprised by this sort of bidirectional relation between
table.search()
and the "user-filtering"input
tag!Fortunately, this feature doesn't break my workaround, since the
keyup
event keeps fired only when it's the user that enters something in this area.I still have (more than) a lot to discover about DataTables
Fred