What would be the best way to add data-hooks to table row data - react-virtualized

I want to add an additional property to each row in a React-Virtualized table so that automation can have an easier job identifying the resultant row data and then verifying it.
Looking at the docs and the code it appears that the easiest would be to simply copy defaultTableRender and modify it to add the data-hook that I want, however I'm reluctant to do this since I don't want the maintenance cost of tracking changes to the original function and porting them forward.
Another option is to wrap result of defaultRowRenderer in a div with the properties that I need, something like:
rowRenderer={(props) => {
return (
<div
key={props.key}
data-hook={data[props.index].id}>
{defaultTableRowRenderer(props)}
</div>
)
}}
This works but seems awfully heavy handed.
Yet another option would be to clone the element and then just add the properties that I want:
rowRenderer={(props) => {
return React.cloneElement(
defaultTableRowRenderer(props),
{'data-hook': data[props.index].id})
}}
This might be the cleanest, though I suspect that I should turn my SFC into a Component and turn my fat arrow renderer into a class function with state so that it's not recreated on every render.
Is there a simpler way that I'm missing?

I think you've pretty much got it right with those 3. My vote would be to fork the default renderer. This would offer you the best performance (though the difference may be pretty trivial). As for your maintenance concerns, the row-renderer is pretty stable.

Related

Tabulator - exclusive header filters - how?

I wrote and support a little web app for our local animal shelter to help volunteers locate dogs. I chose Tabulator because it had great features and was easy to use and have been very happy with my choice. For the first version of the app I used external input fields to search and manually did all the wiring to support live search.
Now I am working on v2 and am trying to use header filters. My problem is that the filters need to be exclusive, that is, using filter1 clears/disables filters 2 and 3, using filter2 clears/disables 1 and 3, and so on. With the external search fields I used focus() events to do this. When I try using jQuery on(focus) delegates to do the same with header filters and for example table.setHeaderFilterValue("field1", "") it does not work; the event triggers but the input box never gets the focus so I cannot type in it. I've tried different events like click; but nothing I've tried works properly.
I've studied the docs and struggled with this for several hours. I've considered hooking dataFiltering() and eliminating the filters I don't want, but I'm not sure how to identify the filter that I want to keep, and there is still the matter of the text in the fields to be dealt with. I'm sure it doesn't help that front-end work is not my area of expertise, though so far I've managed well enough. Is there a simple or normal way to do this that I'm just not seeing?
For the record, I found a way to do exclusive filtering with header filters with a single event callback:
\$(document).on("focus", ".tabulator-col input[type=search]", function() {
var hfNames = ["name", "anum", "kennel"];
var fieldName = \$(this).closest(".tabulator-col")[0].getAttribute("tabulator-field");
hfNames.map(function(hfN) { if (hfN != fieldName) table.setHeaderFilterValue(hfN, "") });
});
The three hfNames are the field names of the columns with filtering on. Yes, I could have derived them dynamically, but it didn't seem worth it for a small app like this.
As I suspected, the key was simply a better knowledge of JQuery.

Update XPages text value from within a repeat?

I feel like I'm just not understanding something about the XPages lifecycle here. I have an xp:text control, with a value of viewScope.count. Initially, that's null. After the xp:text, I have a repeat that's performing a calculation and returning an array of objects for its value. At the end of the repeat's value section, I'm trying to update the xp:text with a count of the things in the array:
viewScope.count = myArray.length;
The xp:text isn't being updated with that value, though. Should this work? Do I need to do a manual refresh of the xp:text when I modify viewScope.count? TIA!
You should be able to use the index of the repeat to give you a count.
Take a step back and rethink the approach. Inside the code you use for your repeat you update something outside.
Not looking at 'does it work' I would claim 'bad idea'. Such side effects make maintenance a nightmare (and are not very MVC).
The better approach (IMHO):
Create an object data source. AFAIK that can be a JSON object if you are not comfortable with Java. That object would have all the needed properties for your repeat and your counter display. It serves as your model.
Then bind the repeat and the text field to the model and you are good.
Makes sense?

Is this the right way to filter channel entries using conditional variables?

Is this the most efficient way to filter a load of channel entries? I want to display entries that have no comments and that are not sticky. I'm using this code.
{exp:channel:entries channel="{segment_3}" status="open" orderby="date" disable="categories|category_fields|member_data|pagination"}
{if comment_total == "0" AND sticky == 'n'}
...
{/if}
{/exp:channel:entries}
Cheers
Lee
Using conditional variables, probably. But this will likely return lots more results than you need. Plus you won't be able to accurately use {count} (maybe not an issue for you, though).
Another approach which doesn't use conditional variables, but just goes straight after the results you want, and only the results you want, is to use the Query Module
{exp:query sql=
"SELECT title
FROM exp_channels
JOIN exp_channel_titles ON exp_channels.channel_id = exp_channel_titles.channel_id
WHERE exp_channels.channel_name = '{segment_3}'
AND exp_channel_titles.status = 'open'
AND exp_channel_titles.sticky = 'n'
AND exp_channel_titles.comment_total = 0"
}
<li>{title}</li>
{/exp:query}
This could get tedious if you needed to access a bunch of custom fields, but it is an efficient way to get the results you want.
Sticky is an available parameter on the entries loop, so you could filter at least that element in the entries loop itself by simply adding sticky="no", but comments, unfortunately, is not an available parameter, so Alex's suggestion may be the best option if your requirements are fairly simple. If you need access to a significant number of custom fields, however, it may be a bit tricky. So you'll have to decide what approach to take based on what you need within your loop.

Expression Engine - Is it possible for exp:channel:entries tag to have complex filters?

Coming from Codeigniter and new to Expression Engine, I am at a loss on how to do complex filters on the exp:channel:entries tag.
I am interested in this filters
status
start_on
stop_before
How do you do you implement filters for a complex condition like this?
(status=X|Y|Z AND start_on=A AND stop_before=B) OR (status=X AND start_on=C AND stop_before=D)
Is this even possible?
You can only use the search= parameter to search on “Text Input”, “Textarea”, and “Drop-down Lists” fields unfortunately. So you'd need to use the query module for this.
If you're just querying on those parameters you should be able to get the entry id's you need from the exp_channel_titles table, then use something like the Stash plugin to feed the entry_id's of the results into a regular channel entries tag. Yes it's nominally one more query that way but as EE abstracts the db schema fairly heavily the alternative is to get lost in a mess of JOINs.
So something like (pseudocode, won't work as is):
Get the entries, statuses are just a string in exp_channel_titles, entry_date is the date column you want - which is stored as a unix timestamp, so you'll need to select it with something like DATE( FROM_UNIXTIME(entry_date)) depending on the format of your filter data.
{exp:stash:set name="filtered_ids"}{exp:query sql="SELECT entry_id
FROM exp_channel_titles
WHERE status LIKE ...<your filter here>"
backspace="1"
}{entry_id}|{/exp:query}{/exp:stash:set}
Later in template:
{exp:channel:entries
entry_id="{exp:stash:get name="filtered_ids"}"
}
{!--loop --}
{/exp:channel:entries}
Yes it's a mess compared to what you're probably used to in pure CI, but the trade off is all the stuff you get for free from EE (CP, templating, member management etc).
Stash is awesome by the way - can be used to massively mitigate most EE performance issues/get around parse order issues
You can get a lot of this functionality using the search= parameter in your {exp:channel:entries...} loop.
It's not immediately clear to me how you'll get the complexity you seek, so you might end up resorting to the query module though.
If you're working with dates you might find the DT plugin useful.

Can you use dynamic finders or grouping tables via scaffold in Grails?

I'm working on a very, very quick and dirty application using almost entirely scaffold to do it. This is only for internal use, and it's just to replace a spreadsheet, so while I know that I shouldn't rely on scaffolds for real production use, I still intend to use them where I can for efficiency (...just wanted to make sure we aren't taken off track by the inevitable question!).
What I am curious about is since scaffolds can do quick and dirty CRUD, and you can do dynamic finders for searches, is there a way to dynamically show the "list" action of the scaffold with a constraint (i.e. show all items in the list that were created by this "user")? That would be fine for me...
Alternatively, is there anything available in Grails to allow "grouped" tables. Essentially the "list" action from the scaffold, but grouped by a particular attribute (again, think of grouping all the items by the user that created them).
Any help would be appreciated - I've scoured Google and some books with no luck, but wanted to check with the StackOverflow community before I dismiss the notion and write it by hand. Thanks!
We did the same in our Grails application and it's relatively easy:
Create a new form in the list.gsp referring to the list action <g:form action="list" method="post">
Inside that form, declare a table with the fields you want to search on:
<div class="buttons">
<span class="button"><g:submitButton name="list" class="search" value=" ${message(code: 'default.button.search.label', default: 'Search')}"/></span>
</div>
In the list action, build up the query (using findAll, findWhere, .. whatever takes your fancy) and return that to the page:
[wardInstanceList : Ward.findAll(whereClause, [max: params.max, offset: params.offset]) , wardInstanceTotal : (int) Ward.executeQuery("select count(*) " + whereClause).get(0)]
The whereClause looks something like: "from Ward where ward = 'something' and room = 'something else'"

Resources