I'm using the following package to do paging in ASP.NET MVC
https://github.com/TroyGoode/PagedList
This is wokring great, however I'd like to be able to add a extra HTML5 data attribute to the pager links. Simply which contains the page number of the link.
For example:
1 2 etc etc
But I'm struggling to do this and can only get the page number into the URL.
Can anyone help? I would have thought this would have been a common and useful feature.
Thanks
Sorted with some help from Troy, working perfect now :)
#Html.PagedListPager(Model, page => "admin/demo/userlist", new PagedListRenderOptions { FunctionToTransformEachPageLink = (liTag, aTag) => { aTag.Attributes.Add("data-page-no", aTag.InnerHtml); liTag.InnerHtml = aTag.ToString(); return liTag; } })
Short deadline hack. I tried something similar, but if the inner HTML for the hyperlink is an ellipse or some other special character, it didn't quite work.
FunctionToTransformEachPageLink = (li, a) =>
{
if (a.Attributes.ContainsKey("href"))
{
Uri uri;
if (Uri.TryCreate("http://temp.org/" + a.Attributes["href"], UriKind.Absolute, out uri))
{
var qs = uri.Query;
if (!string.IsNullOrWhiteSpace(qs))
{
var nvc = HttpUtility.ParseQueryString(qs);
var page = nvc["page"];
a.MergeAttribute("data-page", page);
}
}
}
else
{
int page;
if (int.TryParse(a.InnerHtml, out page))
a.MergeAttribute("data-page", page.ToString());
}
li.InnerHtml = a.ToString();
return li;
}
"FunctionToTransformEachPageLink" should include the current page as a delegate parameter.
Using "latest" 8.0.7 nuget X.PagedListMvc.Core the FunctionToTransformEachPageLink delegate is adding and additional element when passing return value. So if you return liTag the page number link will be doubled. The working code is below, just returning an empty tag builder:
FunctionToTransformEachPageLink = (TagBuilder liTag, TagBuilder aTag) =>
{
var ret = new TagBuilder("text");
aTag.Attributes.Add("data-otf-target", "#page-wrapper");
liTag.InnerHtml.AppendHtml(aTag);
return ret;
},
If anyone has a better solution please edit this post.
Related
Is it possible to set the background color for a row in slickgrid (based on data values) AND use pagination? For angular-slickgrid package.
I used getItemMetadata as suggested multiple other (old) posts - example SlickGrid: How to loop through each row and set color based on the condition?.
This code:
metadata(old_metadata_provider) {
return function(row) {
var item = this.getItem(row);
var ret = (old_metadata_provider(row) || {});
if (item) {
ret.cssClasses = (ret.cssClasses || '');
if ("attribute" in item) {
return { cssClasses: 'redRow' }; //redRow is in styles.css
}
}
return ret;
}
}
and the call is:
this.dataViewObj.getItemMetadata = this.metadata(this.dataViewObj.getItemMetadata);
It works correctly. However, when I turn pagination on, the color does not work as expected. I read that SlickGrid re-uses the same row elements when scrolling or paginating and will overwrite the styles associated with them. Is there another way to do it? Thanks for any help on this.
I tried adding the following code, after reading suggestion from ghiscoding, but the colors are still not working when pagination is enabled.
angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.dataViewObj = angularGrid.dataView;
this.gridObj = angularGrid.slickGrid;
this.checkRowBackgroundColor(); //where I call the metadata function from my previous post, if the dataView object is defined.
//I added this code:
var self = this;
this.dataViewObj.onPagingInfoChanged.subscribe(function (e, dataView, grid) {
self.gridObj.invalidate();
self.gridObj.render();
});
}
Try this approach:
angularGridReady(angularGrid: AngularGridInstance) {
this.angularGrid = angularGrid;
this.dataViewObj = angularGrid.dataView;
this.gridObj = angularGrid.slickGrid;
// check color change logic for the first time page load
this.checkRowBackgroundColor();
// use arrow function so that 'this' works properly
this.dataViewObj.onPagingInfoChanged.subscribe((e, dataView, grid) => {
// check your color change logic every time Paging Info Changed
this.checkRowBackgroundColor();
});
}
Inside your checkRowBackgroundColor:
checkRowBackgroundColor() {
// ... any of your logic
// get metadata
this.dataViewObj.getItemMetadata = this.metadata(this.dataViewObj.getItemMetadata);
// rerender the grid after getting new metadata
this.gridObj.invalidate();
this.gridObj.render();
}
Your problem should be solved now. As I have not tested on my local machine, I can not give guarantee. You can checkout original documentation of angular-slickgrid about this specific topic here: Dynamically Add CSS Classes to Item Rows
I have the following helper defined:
$.views.helpers({
total: function(lines) {
var total = 0;
for (var i = 0; i < lines.length; i++) {
total += lines[i].price * lines[i].quantity;
}
return total;
}
});
Then I have have the following code to data link my model to my view:
var model = {
lines: []
};
$("#lines").link(true, model);
Finally within the view I have the following:
<span data-link="~total(lines)"></span>
However whenever I observably add or remove items from the array it doesn't update the total. I read that you could pass in lines.length into the function and indeed it updated the total each time I added or removed an item. But when I observably updated the quantity property against any of the lines the total did not update.
I'd appreciate it if someone could show me how to do this.
Thanks
Yes, as you found with https://github.com/BorisMoore/jsviews/issues/280, there is not currently a declarative syntax for depending on "All". Probably after V1.0 that feature will be added - along the lines of total.depends = "lines**"; or total.depends = "lines*.*"; for a helper: function total(...)...
Meantime you can use a programmatic approach - which is still very easy. Just trigger a refresh by adding:
$.observable(model.lines).observeAll(function() {
$("#lines").link(true, model);
})
or refresh just the 'total' span by writing:
<span id="total" data-link="~total(lines)"></span>
and
$.observable(model.lines).observeAll(function() {
$("#total").link(true, model);
})
See for example: http://jsfiddle.net/BorisMoore/wch601L9/
I've found the following issue which has a couple of suggested fixes:
https://github.com/BorisMoore/jsviews/issues/280
Unfortunately both are abit of a hack but I guess it will have to do for now.
I'm using Fishpigs Wordpress integration module in a Magento store. When I set it to use a custom Wordpress menu, which I've set up in Wordpress with some category hierarchies, it doesn't add any active states if you've clicked a link and are on an "active" page. After digging about, /app/code/community/Fishpig/Wordpress/Model/Menu/Item.php has the following:
public function isItemActive()
{
return false;
}
So it seems like they've just skipped this bit? Anyone any idea how to set active states here?
OK, this seems to do the job, bit of a workaround but hey!
public function isItemActive()
{
$currurl = Mage::helper('core/url')->getCurrentUrl();
$linkurl = $this->getUrl();
if(strstr($linkurl, $currurl)){
return true;
}
else {
return false;
}
}
Get the current url, get the blog url, if they match set active state to true. I then used a bit of jQuery to set states of parents to active as the above only sets the current link:
$('#nav li.nav-3 ul li.level1.active').parent().parent().addClass("active");
...where li.nav-3 is the parent blog link
Replace the isItemActive function with following code in /app/code/community/Fishpig/Wordpress/Model/Menu/Item.php. This is working for me.
public function isItemActive() {
$myblogUrl = Mage::helper('wordpress/abstract')->getBlogRoute();
$mycurrentUrl = preg_replace('/\?.*/', '', Mage::helper('core/url')->getCurrentUrl());
if (in_array($myblogUrl, explode("/", $mycurrentUrl))) {
return true;
} else {
return false;
}
}
The problem is just a simple miss.. Magento uses a "/" in all urls,$currentUrl never matches $currentUrl because of this. The correction is just to trim the "/" I know a late response, but thought it may help someone.
public function isItemActive()
{
$currentUrl = Mage::getUrl('*/*/*', array('_current' => true, '_use_rewrite' => true));
if (strpos($currentUrl, '?') !== false) {
$currentUrl = substr($currentUrl, 0, strpos($currentUrl, '?'));
}
return $currentUrl === rtrim($this->getUrl(), '/');
}
I am beginning the process of moving away from the AjaxControlToolkit and toward jQuery. What I want to do is have one function that duplicates the functionality of the CollapsiblePanelExtender. For a particular set of hyperlink and div, the code looks like this:
$('#nameHyperLink').click(function() {
var div = $('#nameDiv');
var link = $('#nameHyperLink');
if (div.css('display') == 'none') {
link.text('Hide Data');
div.show(400);
}
else {
link.text('Show Data');
div.hide(400);
}
});
What I really want to do is only have to write this function once, then use it for many (approx 40) instances throughout my website. Ideally what I want is this:
function showHidePanel(divID,linkID,showText,hideText){
var div = $(divID);
var link = $(linkID);
if (div.css('display') == 'none') {
link.text('Hide Data');
div.show(400);
}
else {
link.text('Show Data');
div.hide(400);
}
});
I would then call this function from every HyperLink involved using OnClientClick.
Is there a way to do this?
Have you looked at the jquery accordian plugin?
I am using dojo datagrid to display my data. When the end user edit the cell values it should be updated in the server using ajax calls(when the focus goes out of the cell).
Else, I should have a Edit & update/cancel buttons for each row to handle the same feature.
But I don know how to place edit & update buttons inside the grid and capture their events.
By default dojo updates only local the store value(client side). how can I save the updated cell values into the server?
do we need to write any override methods to do so??
I am new to dojo. Any detailed explanation or sample codes would be much appreciated.
Could anyone lend a hand to solve this issue??
Thank you
Regards,
Raj
To be able to push the updates server-side, you've to override _saveCustom() or _saveEverything(). Here is a piece of code (a bit cleaned-up) I'm using to persist an update.
Note that the code below relies on the private _getModifiedItems() because the DataGrid accepts inline editions. If you do know the list of modified items (because the edition is done in a popup and you keep the item key somewhere), retreiving the modified item is simpler.
module.submitUpdates = function() {
var store = <from a variable local to the module>
if (store.isDirty() confirm("Updates to be persisted. Continue?")) {
store._saveCustom = function(saveCompleteCallback, saveFailedCallback) {
var modifiedItem = _getModifiedItems(store)[0];
dojo.xhrPost( {
headers: { "content-type": "application/json; charset=utf-8" },
content: dojo.toJson(modifiedItem),
handleAs: "json",
load: function(response) {
if (response !== null && response.success) {
saveCompleteCallback();
}
else {
saveFailedCallback(response);
}
},
error: saveFailedCallback,
url: "/API/<Object>"
});
};
store.save( {
onComplete : function() {
module.loadCachingRuleList();
},
onError : function(errorData, request) {
_reportUpdateFailure(errorData, errMsg);
}
});
}
};
Here is the code I use to get all updated items when the user is about to loose an updated DataGrid (because he leaves the page or because he wants to refresh the grid content).
Note that the following code was using Dojo 1.3. I haven't check if it's easier with Dojo 1.4... I hope that dojo.Stateful that's going to be introduced in Dojo 1.5 will simplify it, otherwise we'll have to wait for Dojo 1.6 ;)
var _getModifiedItems = function(store) {
var modifiedItems = [];
if (store !== null && store._pending !== null) {
if (store._pending._modifiedItems !== null) {
for (var modifiedItemKey in store._pending._modifiedItems) {
if (store._itemsByIdentity) {
modifiedItems.push(store._itemsByIdentity[modifiedItemKey]);
}
else {
modifiedItems.push(store._arrayOfAllItems[modifiedItemKey]);
}
}
}
if (store._pending._newItems !== null) {
for (var modifiedItemKey in store._pending._newItems) {
if (store._itemsByIdentity) {
modifiedItems.push(store._itemsByIdentity[modifiedItemKey]);
}
else {
modifiedItems.push(store._arrayOfAllItems[modifiedItemKey]);
}
}
}
}
return modifiedItems;
};
var _getDeletedItems = function(store) {
var deletedItems = [];
if (store !== null && store._pending !== null && store._pending._deletedItems !== null) {
for (var deletedItemKey in store._pending._deletedItems) {
if (store._itemsByIdentity) {
deletedItems.push(store._itemsByIdentity[deletedItemKey]);
}
else {
deletedItems.push(store._arrayOfAllItems[deletedItemKey]);
}
}
}
return deletedItems;
};
I hope this helps,
A+, Dom
This isn't a very detailed explanation but yes you should override the method that handles user data entries as I don't see an event for this. So basically create a new class that inherits from the data grid, find the method in the source code that handles the editing and override it to give it an extra action to post it back to the server. You'll want to call the datagrid's default action in that method too.
Some information here (that you probably are already aware of):
http://docs.dojocampus.org/dojox/grid/DataGrid#editing-data
I've extended Dojo's default components before, it's not hard. I find that it's always good to examine the Dojo source and to just be careful when upgrading Dojo to make sure new versions don't break existing features.
To avoid hacking your dojo library, just switch to the YUI2 data table; it's cell editor accepts the asyncsubmitter function that sends your edits to your sever
This is the description from documentation
asyncSubmitter
Function
Implementer defined function that can submit the input value to a server. This function must accept the arguments fnCallback and oNewValue. When the submission is complete, the function must also call fnCallback(bSuccess, oNewValue) to finish the save routine in the CellEditor. This function can also be used to perform extra validation or input value manipulation.
YUI2DataTable