I am using the data table with my ASP.NET MVC 3 web application and so far it is going quite well. I connect to a SQL Server 2008 database, and I return data by using a stored procedure. I am using IE 8 and the latest version of Firefox. The version of YUI is 2.8.2r1. I have a couple of questions regarding the data table :)
Here is my data table's code:
<script type="text/javascript">
YAHOO.util.Event.onDOMReady(function () {
var grdNewsColumnDefs, grdNewsDataSource, grdNewsConfigs, grdNewsDataTable;
// News list data table
var formatActionLinks = function (oCell, oRecord, oColumn, oData) {
var newsId = oRecord.getData('NewsId');
oCell.innerHTML = 'Edit | ' +
'Details';
};
var formatActive = function (oCell, oRecord, oColumn, oData) {
if (oData) {
oCell.innerHTML = "Yes";
}
else {
oCell.innerHTML = "No";
}
};
grdNewsColumnDefs = [
{ key: 'Title', label: 'Title', className: 'align_left' },
{ key: 'Active', label: 'Active', className: 'align_left', formatter: formatActive },
{ key: 'Action', label: 'Actions', className: 'align_left', formatter: formatActionLinks }
];
grdNewsDataSource = YAHOO.util.DataSource('#Url.RouteUrl(Url.NewsJsonList())');
grdNewsDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
grdNewsDataSource.responseSchema = {
resultsList: 'DataResultSet',
fields: [
{ key: 'NewsId' },
{ key: 'Title' },
{ key: 'Active' },
{ key: 'Action' }
]
};
grdNewsConfigs = {
paginator: new YAHOO.widget.Paginator({
rowsPerPage: 20
})
};
grdNewsDataTable = new YAHOO.widget.DataTable('grdNews', grdNewsColumnDefs, grdNewsDataSource, grdNewsConfigs);
grdNewsDataTable.on('initEvent', function () {
YAHOO.util.Dom.setStyle(grdNewsDataTable.getTableEl(), 'width', '100%');
});
});
</script>
Not sure what I am doing wrong, but here is my action method that returns my data:
public ActionResult JsonList()
{
JsonEncapsulatorDto<News> data = new JsonEncapsulatorDto<News>
{
DataResultSet = newsService.FindAll()
};
return Json(data, JsonRequestBehavior.AllowGet);
}
I put a breakpoint on the return Json... line to see if this action method is hit. When the page loads the first time it goes to the break, I hit F5 then it runs and displays the view with the populated grid. When I refresh my browser by pressing F5 then my breakpoint is not hit again, I'm not sure why, it never goes in here again.
How is data loaded into the grid? If I have 100 records in the table and I have set my rowsPerPage to 20 then I will have 5 pages. Given my code above, is data loaded all at once, meaning is all 100 rows loaded at once? I would preferably like to have it loaded in "chunks" instead of having it all loaded at once. In another table I have much more records and this will not be a wise design approach to load everything at once. How would I implement something like this?
I am trying to style certain table headers and cells in the data table. I worked through this article explaining how to style a data table: http://www.satyam.com.ar/yui/widgetstyles.html. When I set the td to right align then the th for that column is also right aligned, why is this? You can see above how I set the className property. Here is my stylesheet code:
.yui-skin-sam .yui-dt td.align_left{text-align:left}
Given the above scenario, I want the column header to be left aligned and the corresponding column rows to right aligned? I probably won’t use it like this, but just want to know how to set a style to different elements?
I set the data table's width to be 100%, but when I page to the next page then it seems to loose this width of 100%. Why is this? What I need to do to have my data table to keep my width of 100%?
If I were to update data then it does not display as updated. Why is this and what do I need to do get the updated data to display in the data table?
You have configured your YUI grid to use an AJAX request to fetch the remote data:
grdNewsDataSource = YAHOO.util.DataSource('#Url.RouteUrl(Url.NewsJsonList())');
GET AJAX requests could be cached by the browser which explains why your controller action is hit only once (the first time you load the page). In order to avoid this caching you could either configure YUI to use a POST request or append a random number to the URL each time the page is loaded.
How is data loaded into the grid? If I have 100 records in the table and I have set my rowsPerPage to 20 then I will have 5 pages.
No matter what you set on the client side the following:
DataResultSet = newsService.FindAll()
is a clear indication that the server fetches all records from the database and sends all records back to the client and it is the client that retrieves only the necessary records to show which is inefficient.
Ideally the pagination should be done on the server. Here's an example from the documentation. The client sends the startIndex and results parameters to the server so that it could paginate the data set on the server and return only the necessary rows that will be shown on the screen.
Related
I've searched and I've searched and I've searched, I can't find an answer to this.
I am using Angular Firestore to fetch data (tried both snaphotChanges and valueChanges). The code works.
However, if the data changes on the backend, the material table row on the UI only refreshes automatically when either I am showing all the data or if I disable paging. However, when paging is enabled, the UI resorts to show that the data got updated, but it does not refresh the cell value until I move the cursor on the row to force a refresh. I don't know if it's a bug or if I am doing something wrong.
I made a video showing what happens: https://youtu.be/SN6EFc6Vqm8
// Have this in my service. It works
getContactsByLimit(limit) {
return this.afs
.collection("users")
.doc(this.user.currentUserId)
.collection("contacts", ref =>
ref
.orderBy("id", "desc")
.limit(limit)
)
.valueChanges();
}
// The paginator declaration
#ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
// This works
this.contactsSubscription = this.contactsvc
.getContactsSnapshotChangesByLimit(3)
.subscribe(contacts => {
// This works, I get new data.
this.dataSource.data = contacts;
});
// HTML template
<mat-paginator class="paginator"
[length]="15" // This breaks the refresh
[pageSize]="3"
[pageSizeOptions]="[2,3,5]"
(page)="pageEvent($event)"></mat-paginator>
// The automatic refresh does not work if I set
// the length to be > 3 in this case (unless I move
// the mouse on the table).
The UI should refresh with new data whether the length > pageSize or not.
Figured it out. I was using trackBy to track by ID. I added a timestamp field in my document and started tracking by timestamp.
<table [dataSource]="dataSource" [trackBy]="trackByTimestmamp" mat-table>
and
trackByTimestmamp(index, item) {
return item.timestamp;
}
This forces the material table to update the table when the timestamp changes.
I need to simulate a drag & drop on fullcalendar in the week view with protractor. I found something with coordinates but I'd like a "no browser window dependent solution"... ther's also no way out on finding the exact starting cell in the week view by class or id ...or at least, I couldn't figure how to select a single cell of a row of a day because, using the Chrome's item selector, it seems every row has the same class fc-widget-content and cells are not "selectable" elements.
Are there any other chances?
maybe this is a little bit helpful (also very later ;). I also want to test my app with FullCalendar, but I'm using Cypress (similar to Protractor).
We plan items from an external list and assign it to a resource on a certain day/time in the FullCalendar (we use the scheduler plugin).
I found out that the drag and drop event is somehow intercepted by code, enriching it with for example properties of the event (like date, title and others). How I enriched this data is in the Cypress trigger('drop', data) command. Data is the evenData that is set by the Draggable class:
// Executed on the external list items, where every item we want to plan has class `.fc-event`.
this.draggableContainer = new Draggable(this.containerEl.nativeElement, {
itemSelector: '.fc-event',
eventData(eventEl) {
const id = eventEl.dataset.id;
return {
duration,
id: currentWorkItem.id,
title: currentWorkItem.description,
extendedProps: {
duration,
customRender: true,
data: currentWorkItem,
},
};
}
Then, in your test file (Cypress)
const eventData = {
date: new Date(),
dateStr: new Date().toISOString(),
draggedEl: {
dataset: {
notificationId: '123',
priority: '0',
title: 'Test',
},
},
jsEvent: null,
resource: {
id: '123',
},
event: null,
oldEvent: null,
};
cy.get('.fc-event') // selector for the external event I want to drag in the calendar
.trigger('dragstart')
.get('.fc-time-grid table tr[data-time="07:00:00"] td.fc-widget-content:nth-child(2)') // selector for where I want to drop the event.
.trigger('drop', eventData) // this will fire the eventDrop event
So, .trigger('drop', eventData) will fill the eventDrop info. It is not exactly the same as doing it manually, but works for me.
Caveats:
I haven't found a way to plan it on another resource (we use the resource scheduling plugin of FullCalendar.io). It does not matter that much, because you can specify it in the evenData (resource: { id: 'my-resource-id' } }.
No visual feedback because the drag mirror is not shown. Not a big problem during e2e testing, but it is a bit of a blackbox now. Maybe this is fixable
I have a many-to-many relationship in mongodb between Players and Tournaments.
I want to be able to add many Players to a Tournament at once. This is trivial to do without ajax, but we have a DB of thousands of Players, and so the form select becomes huge.
We want to use ajax for this. Is it possible to create a single widget (with js) to handle this properly? If so, any hints on what jquery plugin (or other) to use?
If not, whats the standard strategy to do this? I suppose I could heavily change the view for this form and use an ajax autocomplete to add one player at a time, and then some more code to delete each player one at a time. However, I'd really like to have a single widget I can re-use because its so much cleaner and seems much more efficient.
I have been playing with Select2 all day (similar to jQuery Chosen) and I have it working for adding many Players via ajax, but it does not allow me to set the already attached players when I initially load the page, so I won't be able to see who's already in the tournament and would have to retype everyone in.
Thanks for ANY input on this matter! I can't find anything via Google.
I was able to accomplish this by $.ajax after the constructor within the onload function where //website/jsonItem is a json-encoded list of all items, and //website/jsonItemUser is a json-encoded list of all items attached to user. I used // to keep the https/http consistent between calls.
$(document).ready(function(){
$('.selectitem').select2({
minimumInputLength:0
,multiple: true
,ajax: {
url: "//website/jsonItem"
,dataType: 'jsonp'
,data: function (term, page) {
return {
q: term, // search term
limit: 20,
page: page
};
}
,results: function (data, page) {
var more = (page * 20) < data.total;
return {
results: data.objects, more: more
};
}
}
,initSelection: function(element, callback){
var items=new Array();
$.ajax({
url: "//website/jsonItemUser"
});
callback(items);
}
});
$.ajax({
url: "//website/jsonItemUser"
,dataType: 'jsonp'
,success: function(items, status, ob) {
$('.selectitem').select2('data',items);
}
});
});
I have a grid panel containing store displayed on many pages (using PagingToolbar).
On the tbar, I put the button to have a query for all data in store according record.get("criterion"). I've tried using queryBy, but it's returning none. So, I use filterBy in button handler, as coded below:
new Ext.Button(
{
text: 'Query',
icon: 'img/icon_search.gif',
scope: this,
handler:function(){
my_store.filterBy(
function(record, id) {
return record.get('field_name') == 'The Content of Field Name';
});
}
}
),
Unfortunately, the query (filter) above only search on current page of grid. How to get all filtered (queried) data from other pages that doesn't displayed?
Look at using remoteFilter on your store, or using the GridFilter plugin.
store.filterBy(function(record)
{
return lines.indexOf(record.get("line_code")code)>0?true:false;
},store.getAllRange()
Can someone please throw some light on how to go about rendering an hyperlink in the cells of a particular column in ExtJS?
I have tried binding the column to a render function in my JS, from which I send back the html:
SELECT
However, with this, the problem is that, once I hit the controller through the link, the navigation is successful, but subsequent navigations to the data-grid show up only empty records.
The records get fetched from the DB successfully through the Spring MVC controller, I have checked.
Please note that this happens only once I use the row hyperlink in the extJS grid to navigate away from the grid. If I come to the grid, and navigate elsewhere and again come back to the grid, the data is displayed fine.
The problem only occurs in case of navigating away from the grid, using the hyperlink rendered in one/any of the cells.
Thanks for your help!
This is for ExtJS 4 and 5.
Use a renderer to make the contents look like a link:
renderer: function (value) {
return ''+value+'';
}
Then use the undocumented, dynamically generated View event cellclick to process the click:
viewConfig: {
listeners: {
cellclick: function (view, cell, cellIndex, record, row, rowIndex, e) {
var linkClicked = (e.target.tagName == 'A');
var clickedDataIndex =
view.panel.headerCt.getHeaderAtIndex(cellIndex).dataIndex;
if (linkClicked && clickedDataIndex == '...') {
alert(record.get('id'));
}
}
}
}
Try something like this:
Ext.define('Names', {
extend: 'Ext.data.Model',
fields: [
{ type: 'string', name: 'Id' },
{ type: 'string', name: 'Link' },
{ type: 'string', name: 'Name' }
]
});
var grid = Ext.create('Ext.grid.Panel', {
store: store,
columns: [
{
text: 'Id',
dataIndex: 'Id'
},
{
text: 'Name',
dataIndex: 'Name',
renderer: function (val, meta, record) {
return '' + val + '';
}
}
...
...
...
However my thanks to - ExtJS Data Grid Column renderer to have multiple values
Instead of using an anchor tag, I would probably use plain cell content styled to look like an anchor (using basic CSS) and handle the cellclick event of the GridPanel to handle the action. This avoids dealing with the anchor's default click behavior reloading the page (which is what I'm assuming is happening).
I created a renderer so it looked like you were clicking on it.
aRenderer: function (val, metaData, record, rowIndex, colIndex, store){
// Using CellClick to invoke
return "<a>View</a>";
},
But I used a cell event to manage the click.
cellclick: {
fn: function (o, idx, column, e) {
if (column == 1) // Doesn't prevent the user from moving the column
{
var store = o.getStore();
var record = store.getAt(idx);
// Do work
}
}
}
For these purposes I use CellActions or RowActions plugin depending on what I actually need and handle cell click through it.
If you want something that looks like an anchor, use <span> instead and do what #bmoeskau suggested.
You can use 'renderer' function to include any HTML you want into cell.
Thanks guys for your response.
AFter debugging the extJS-all.js script, I found the issue to be on the server side.
In my Spring MVC controller, I was setting the model to the session, which in the use-case I mentioned earlier, used to reset the "totalProperty" of Ext.data.XmlStore to 0, and hence subsequent hits to the grid, used to display empty records.
This is because, ext-JS grid, checks the "totalProperty" value, before it even iterates through the records from the dataStore. In my case, the dataStore had data, but the size was reset to null, and hence the issue showed up.
Thanks to all again for your inputs!