How to redraw whole table after changing theme? - styles

I'm using ag-grid 29 in React. I can change the style from Balham to Alpine on the fly. My problem: Neither the heard rows nor the data rows are then tall enough. Is it possible to accomplish this?
Here's the "before" - my table in Balham:
Here's the "after" - my table in Alpine. Please note the text overflowing the row height:
Here are the methods I call after the style change:
gridApi.refreshHeader()
gridApi.refreshCells()
gridApi.redrawRows()
gridApi.sizeColumnsToFit()

The official demo appears to destroy and recreate the entire grid when you change the theme dropdown, by passing a new React key to the grid component:
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const theme = params.get('theme') || 'ag-theme-alpine';
setGridTheme(theme);
}, []);
<div id="myGrid" className={gridTheme}>
<AgGridReactMemo
key={gridTheme}
// ...
/>
</div>
Actual users probably won't change the theme very often, so it's likely not worth putting effort into doing this elegantly. It may be possible to fix everything by calling various functions, but I didn't look in to it.

Related

Alternative to detailinit event in Angular 2 Kendo grid

In the Angular 2 Kendo grid, I need to show additional info in each cell when the user opens the detail template.
In the Kendo Grid for jQuery I could use the detailinit (http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#events-detailInit) event to accomplish what I need, however, there is no such event in the Angular2 component.
<kendo-grid-column>
<template kendoCellTemplate let-dataItem let-rowIndex="rowIndex">
{{rowIndex}}
<div *ngIf="????">
Need to show this text when detail template is visible
and hide when it's hidden
</div>
</template>
</kendo-grid-column>
<template kendoDetailTemplate let-dataItem>
<section *ngIf="dataItem.Category">
<header>{{dataItem.Category?.CategoryName}}</header>
<article>{{dataItem.Category?.Description}}</article>
</section>
</template>
Here is an example what I need (please see the text in the cells).
At this time, the Angular 2 grid does not provide information whether the detail template is expanded or not. Feel free to suggest this as a feature request.
HACK: To hack around this limitation, you can infer the expanded state from the HTML.
See this plunkr.
private icons(): any[] {
const selector = ".k-master-row > .k-hierarchy-cell > .k-icon";
const icons = this.element.nativeElement.querySelectorAll(selector);
return Array.from(icons);
}
private saveStates(): void {
this.states = this.icons().map(
(icon) => icon.classList.contains("k-minus")
);
}
private isExpanded(index): bool {
return this.states[index] || false;
}
While this works, it is far from ideal, and goes against the Angular philosophy, and may break upon rendering changes.

React-Virtualized ScrollSync: How to set an initial scrollTop value?

I'm using the react-virtualized ScrollSync component to sync the scrolling of a couple fixed headers — very similar to the example in the docs.
My question: is it possible to provide an initial scrollTop value to ScrollSync (or its children)? I realize that the better way to do this would be through use of scrollToRow on the Grid component that controls the scroll position — for what it's worth, I am using scrollToColumn for this purpose. But because, vertically, I'm only rendering one very tall cell, scrollToRow doesn't provide the fidelity needed.
I do realize that this is a slightly bastardized use of a grid component, but it all works quite nicely as a horizontal, infinitely loading scroller, while allowing me to re-use an existing component. If I could just set an initial scrollTop, I'd be golden.
Thanks.
Unfortunately this is not currently supported without a bit of a hack.
First, the reason for the hack: Scroll offsets flow in one direction with ScrollSync (main Grid to synchronized Grids). This means that even if ScrollSync accepted default left/top offsets as props- they would get overridden by the first render of the main Grid. I think this is probably the right thing to do to avoid ugliness inside of react-virtualized.
However you could work around it in application code like this if you wanted to:
class YourComponent extends Component {
render () {
// These are arbitrary
const defaultScrollLeft = 300
const defaultScrollTop = 500
return (
<ScrollSync>
{({ clientHeight, clientWidth, onScroll, scrollHeight, scrollLeft, scrollTop, scrollWidth }) => {
if (!this._initialized) {
scrollLeft = defaultScrollLeft
scrollTop = defaultScrollTop
this._initialized = true
}
return (
<div>
<Grid
{...otherSyncedGridProps}
scrollLeft={scrollLeft}
/>
<Grid
{...otherMainGridProps}
onScroll={onScroll}
scrollLeft={defaultScrollLeft}
scrollTop={defaultScrollTop}
/>
</div>
)
}}
</ScrollSync>
)
}
}

Xpages attach event to partial refresh of pager in Data View

In a previous post I asked how to add a bootstrap class to a Data View. The answer was to add the class to the "table.dataview" in a script block. After the table is created the class is applied and all is well.
But when I use a pager the formatting disappears. I am using a partial refresh on the pager to only refresh the data table but doing so means that the bootstrap class does not get applied to the table.
I believe I need to add an event handler that will attach to the refresh action of the dataView to add the class. However I cannot get the event handler to work.
My code for the event handler is below.
<xp:eventHandler refreshMode="partial" submit="true"
id="applyCSS" refreshId="dataView1" event="parialRefresh"
value="what" loaded="false">
<xp:this.binding><![CDATA[#{javascript:"pager1"}]]></xp:this.binding>
<xp:this.action><![CDATA[#{javascript:("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")}]]></xp:this.action>
</xp:eventHandler>
Oliver, the rendered=false was simply a typo - I was testing something and needed to temporarily suppress that.
Oliver and Paul,
Last night I was able to get the partial refresh to work.
I ran across this post by Mark Roden which explained how to do it. There were two different ways to accomplish this, one less and one more efficient. The code I used is below.
<xp:scriptBlock id="scriptBlock3">
<xp:this.value><![CDATA[$('.dataView1PanelWrapper').on("DOMNodeInserted", function(){
$("table.dataview").addClass("table-striped table-hover table-bordered table-condensed")
})]]></xp:this.value>
</xp:scriptBlock>
However, and isn't there almost always a however in Xpages, I have some sortable columns in the view and clicking on the sort brings up the same problem! I lose the class assignment!
So now I would have to intercept that event too, right?
Concerned where this will end. Don't like the idea of DOM Manipulation, and only want to do it if I have too.
I started by using a simple view. It worked great, but for some reason the spacing was messed up in the pagers. I found that by moving the pagers out of the view itself, I was able to get the alignment issue fixed. I think it would be better just to use a view, as I can assign the class directly and won't have to do all this manipulation. It is however very good to know how to do this for the future.
Is that what you would suggest?
==================================================
I have tried Paul Withers suggestion using an output script. This works on the initial page load, but not on any other changes to the data view - when the pager fires, or sorting or any of that. I am close, but no cigar yet. Any suggestions?
<xp:scriptBlock id="scriptBlock5" loaded="false">
<xp:this.value><![CDATA[dojo.require("dojo.behavior");
Behavior = {
".dataview": {
found: function(node) {
dojo.addClass(node,".table-striped table-hover table-bordered table-condensed");
//node.addClass("table-striped table-hover table-bordered table-condensed");
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});]]></xp:this.value>
</xp:scriptBlock>
Move your existing xp:scriptBlock with the working code inside a facet of the xe:dataView. Then the styling will get applied on initial load and on all partial refreshes.
You should call your CSJS stuff to add the class in the onComplete property of the event handler - hard to find, just highlight the event handler object in source code or outline and then open "All properties" to find the "onComplete" property. This event allows CSJS to be called.
BTW: why is the loaded property = false? The event will never we rendered.
dojo.behavior, dojo.ready and dojo.subscribe should allow you to manage this. dojo.behavior allows you to define a particular behaviour for a particular collection of elements which will be retrieved via a Dojo query. dojo.ready will (I believe) run the code when the page initially loads and dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {...} will run the code aftedr a partial refresh.
Here's sample code I used for converting a DataView's category column images to Font Awesome icons, so the Behavior = {...} bit will need amending.
Behavior = {
// Convert xp:pagers to Bootstrap
".catColumn a img": {
found: function(img_node) {
var imgSrc = dojo.getNodeProp(img_node, "alt").toLowerCase();
if (imgSrc.indexOf("collapse") >= 0) {
dojo.place('<i class="fa fa-minus-square"></i> ', img_node, 'replace');
} else {
dojo.place('<i class="fa fa-plus-square"></i> ', img_node, 'replace');
}
}
}
}
dojo.ready(function() {
dojo.behavior.add(Behavior);
dojo.behavior.apply();
});
//Make sure that future pagers are also straightened out
dojo.subscribe("partialrefresh-complete", null, function(method, form, refreshId) {
dojo.behavior.apply();
});

Can a Url.Action specify a route in MVC5?

In our default layout we have our logo wrapped with a URL.Action to navigate back to the home screen. However, if we are in an Area, it tries to navigate to the home controller in that area, which doesn't exist.
Our home controller is Submission. Here is the link in the layout file:
<a class="navbar-brand custm-navbar-brand" href="#Url.Action("Index", "Submission")">
<img src="#Url.Content("~/Content/images/eed-main-logo.png")" alt="E-Editorial Discovery" width="335" height="56">
</a>
If I am in an area like this: /Admin/Security/Index
the above link tries to go to: /Admin/Submission/Index
but it should go to: /Submission/Index
I'm sure there's a better way, but I haven't found it yet.
Specify the area like you would a parameter. So your first line should be:
<a class="navbar-brand custm-navbar-brand" href="#Url.Action("Index", "Submission", new { Area = "AreaName" })">
You could specify the area in the Url.Action call but this can get messy.
Rather than having to specify the area, why not sort the route out itself so it knows to tie it down to that namespace:
context.MapRoute("ExpressCheckoutRoute",
"expresscheckout/stage/{stageName}/{id}",
new { controller = "ExpressCheckout", action = "Stage", area = "FrontEnd", id = UrlParameter.Optional },
new[] { "Web.Areas.FrontEnd.Controllers" }
).DataTokens["UseNamespaceFallback"] = false;
This sorted the issue out for me and I no longer have to specify the area paramter (take note of the last 2 parts to that mapping).

yahoo autocomplete

I'm kind of like stuck trying to implement YUI autocomplete textbox. here's the code:
<div id="myAutoComplete">
<input id="myInput" type="text" />
<div id="myContainer"></div>
</div>
<script type="text/javascript">
YAHOO.example.BasicRemote = function() {
oDS = new YAHOO.util.XHRDataSource("../User/Home2.aspx");
// Set the responseType
oDS.responseType = YAHOO.util.XHRDataSource.TYPE_TEXT;
// Define the schema of the delimited results
oDS.responseSchema = {
recordDelim: "\n",
fieldDelim: "\t"
};
// Enable caching
oDS.maxCacheEntries = 5;
// Instantiate the AutoComplete
var oAC = new YAHOO.widget.AutoComplete("myInput", "myContainer", oDS);
oDS.generateRequest = function(sQuery) {
return "../User/Home2.aspx?method=" + "SA&Id="+document.getElementById("lbAttributes")[document.getElementById("lbAttributes").selectedIndex].value +"&query="+sQuery;
};
oAC.queryQuestionMark =false;
oAC.allowBrowserAutoComplete=false;
return {
oDS: oDS,
oAC: oAC
};
}
</script>
I've added all the yahoo javascript references and the style sheets but it never seems to make the ajax call when I change the text in the myInput box and neither does it show anything... I guess I'm missing something imp...
#Kriss -- Could you post a link to the page where you're having trouble? It's hard to debug XHR autocomplete without seeing what's coming back from the server and seeing the whole context of the page.
#Adam -- jQuery is excellent, yes, but YUI's widgets are all uniformly well-documented and uniformly licensed. That's a compelling source of differentiation today.
To be honest, and I know this isn't the most helpful answer... you should look into using jQuery these days as it has totally blown YUI out of the water in terms of ease-of-use, syntax and community following.
Then you could toddle onto http://plugins.jquery.com and find a whole bunch of cool autocomplete plugins with example code etc.
Hope this helps.

Resources