Creating "Empty" Rows in ui-grid / ng-grid - angularjs

Is there a way to conditionally add "empty" rows to a ui-grid model? The requirements for my project stipulate that we display items by date (very easy), but also display empty rows for days that don't have items on them so that users can see those gaps at a glance (much more difficult).
Somewhat in line with what was being asked in this question, perhaps some sort of grouping by date and inserting an empty group for dates that don't have associated items could work...?
I could create a whole new collection model that combines dates and my actual data and have the ui-grid use that, but that seems extremely inelegant, as it would likely entail a lot of manual reloading of everything when changes are made to the data. Ideally I'd like to just feed my collection of data rows to the grid, but still have it show an extra row with just the date field for dates that don't currently have items.
I actually have this working in a setup using tables and ng-repeat now, but I'm looking to switch to ui-grid or similar to gain benefits of virtual scrolling, etc since I have a lot of editable (and hence, fully-bound) data.
Thanks in advance...

Would something like this meet your needs?
function fillInEmptyDates(startDate, endDate, data) {
var dateToCheck = moment(startDate);
var end = moment(endDate);
var finished = false;
while (!finished) {
if (!Enumerable.from(data).any(function (x) { return dateToCheck.diff(x.YourEntityDateField, 'days') === 0; })) {
var newEntity = { "YourEntityDateField": dateToCheck.clone().toDate() };
data.unshift(newEntity);
};
dateToCheck.add(1, 'days');
if (dateToCheck.diff(end, 'days') === 0) {
finished = true;
}
}
}
To be called like...
fillInEmptyDates(new Date(2014, 6, 30), new Date(2014, 10, 25), $scope.gridOptions.data);
You could perhaps have the first date as the minimum of your current data, and the end date as the max, or adjust according to your needs.
Note that I have used MomentJS for date manipulation and LinqJS for looking through the dates for the data. I'm sure there would be an easy way to loop through the data without using LinqJS if you preferred. (I'm new to JavaScript and find myself hooked on the LINQ stuff I was previously doing in C#.)
The sorting that you specify in the grid options should apply to the newly created rows.
(Sidenote: you might have to play with timezones to get exactly the values you want. If you're seeing duplicates of the dates that do have data, then it may be due to this.)

Related

flatpickr: disable dates previously picked

I am working on a visa calculator and want the user to be able to pick multiple trips (picking entry and exit dates in separate fields) that will be added. I am only using JS.
When creating a new trip, two input fields open up, that get their own individual ids. When showing the calendar, I want to disable all previously picked dates (and dates in between of course). How can I dynamically achieve that?
newFpEntry = flatpickr(#entryDate${entryDateNum},
{maxDate: new Date(entryDate).fp_incr(timeFrameValueCalendar),
disable: [
???
]
});
Hope I described my problem well. I appreciate any idea!
So, I figured something out.
I pushed each new date pair (entry and exit) in form of an object into an array (previously defined), using flatpickr's syntax,
assigning the key from: to the value newEntryDate and the key to: to the value newExitDate
allBlockedDates.push({from: newEntryDate, to: newExitDate});
I inserted the array into flatpickr
newFpEntry = flatpickr(`#entryDate${entryDateNum}`,
{
disable: allBlockedDates
});
Hope this might be helpful for anyone else struggling with a similar problem.

Angular UI-Grid: filtering cross-column or cross-row

I'm still learning about Angular/ui-grid and have gotten stuck and hoping someone can point me in the right direction. When you set up your grid you can turn on filtering with:
$scope.gridOptions.enableFiltering = true;
Then in the columnDefs when you define your grid you can turn on column filtering with various tests (equal to, contains, exact, less than, etc. ) or make up your own - i.e. you can even define your own boolean function to drive the pass/fail of each row for your desired filtering logic. Here's a typical example:
{
field: 'phone',
filter: {
condition: function(searchTerm, cellValue) {
var strippedValue = (cellValue + '').replace(/[^\d]/g, '');
return strippedValue.indexOf(searchTerm) >= 0;
}
},
But this filtering logic ability all seems to be specific to one column. So what if you have a filtering test that is cross-field (simple example: does field A = field B?) or possibly even cross-row (i.e. I actually have a case where I do complex test across sets of rows to determine which rows should be filtered in/out). Is there a standard method for how to do this sort of more global filtering?
I've gotten close to a solution by saving the include/exclude results of the calculation in a hidden column that is not actually displayed, but I cannot seem to get ui-grid to actually execute the filter function on the hidden column. This raises a related question: how can you force the execution of a filtering operation (because I would like to trigger from a control that is not part of the grid)?
I tried to put together a plunkr of the simpler case (does A = B ?): http://plnkr.co/edit/a0BJZVOGGIyP4Q4hxVob?p=preview
I think if I understood how to make that work, perhaps the answer would also answer (or make moot) the dynamic aspect (how to force the filter operation when needed) of the problem as well.
Thanks for any assistance
I've added a cross field example today to the tutorials: http://ui-grid.info/docs/#/tutorial/321_singleFilter
The key is that the base filtering works on a column at a time. It starts with all the rows visible, and then sets a row invisible if it doesn't match any of the individual column filters. What you're asking for is more akin to an OR condition, which the filtering doesn't currently support.
What you can do, though, is build a custom rowsProcessor that applies custom filtering, and the tutorial provides an example of that.
Try something like this
{
field: 'phone',
filter: {
condition: function(searchTerm, cellValue) {
var strippedValue = (cellValue + '').replace(/[^\d]/g, '');
var match1 = strippedValue.indexOf(searchTerm) >= 0;
var match2 = // some Other condition
return (match1 || match2); //add additional matches as needed.
}
},

Disable filtering on a column in ng-grid

I want ng-grid not to search based on specific columns, but I do want those columns to still be sortable.
Is there a way to accomplish this?
Sorry I'm late, meetings all day:-\ Got this running with a modfied version of my answer example from here.
This one is based on the official server sided pagination example from here.
I changed the code in $scope.getPagedDataAsync to include this filtering function:
if (searchText) {
var ft = searchText.toLowerCase();
data = $scope.longData.filter(function(item) {
var si=JSON.stringify(item.allowance).toLowerCase()+JSON.stringify(item.paid).toLowerCase();
if (si.indexOf(ft)!=-1){
return item;
};
});
This will generate a string from the column data fields allowance and paid, ingores the name column, and searches the generated string for any occurrence of the search text. Add more colums to your liking.
If searchtext is found anywhere in the string the item is returned to ng-grid.
This is case insensitive, hence the toLowerCase() part.
Find a working Plunker here.

ExtJS 4.2 Accessing Array Elements returned from store

I am unable to access the store elements returned from my store. When I console.log(me.proxy.read(operation)) and expand/navigate in the console I see all of my elements. There are 1000 rows. I am using the same store for a grid and have the pageSize set to 50. Even though I can see 1000 rows when i do a console.log(me.proxy.read(operation.resultSet.records[51])) i get an undefined message. So, it appears that for some reason the number of elements I can access is only 50 as that is what my pageSize is set to.
Long story short, I am using the same store for two scenarios. I want to have paging in my grid that will show 50 rows on each page. However, I want to loop through the entire store and load an array of all 1000 rows. The reason why I want an array of all 1000 is becasue I am going to use a date field in the rows to populate my date picker from an array. I am going to disable the dates in my grid and have the datepicker display only the dates that are in my grid.
I tried to include a screen shot but I am not allowed because i am only a 3 on the reputation system.
var operation = new Ext.data.Operation({action: 'read', start: 0, limit: 1000});
var proxy = new Ext.data.proxy.Ajax({ url: 'http://192.168.0.103/testit/dao_2.cfc?method=getContent'});
me.proxy.read(operation);
console.log(me.proxy.read(operation));
HERE IS UPDATED CODE:
I have this in my controller:
ondatesStoreLoad: function(me,records,success)
{
var s = this.getStore('dates');
for (i = 0; i < s.getCount(); i++) {
MESSAGE_ID = s.getAt(i).get('message_id');
RECIP_EMAIL = s.getAt(i).get('recip_email');
UNIX_TIME_STAMP = s.getAt(i).get('unix_time_stamp')
console.log(i,MESSAGE_ID, RECIP_EMAIL, UNIX_TIME_STAMP);
};}
This puts out all 1,000 of my records to the console but I am not sure how to put them in an array that I can use in my datepicker component. When ever i try to get the store in the datepicker it is always undefined. I suppose it is becasue the store hasn't loaded yet so there is nothing there. Not sure how to get around that. Perhaps a callback handler?
HERE IS ANOTHER UPDATE:
I added a callback in my store.load:
var store = Ext.getStore('dates');
store.load({callback: function(){
console.log(store.data.items[999].data.recip_email);
console.log(store.data.items[999].data.unix_time_stamp);}
})
That took forever to figure out but now I can access all my records and have a smaller problem to work on. At the moment i just have one element hardcoded to do a quick test.
Where do I need to put the code to get it into my date picker disableDates config? I need to put the dates into an array but for quick testing I used minDate: just to see if i could see something work but it shows up as undefined. Now i have the code in a beforrender listener but that seemingly needs to be in some other place or maybe some handler for my date picker....? is there an onload for the datepicker or something i shoudl use for this??
Why not just change the datepicker directly from that ondatesStoreLoad function? Before the loop, disable all dates in the datepicker. Then during the loop, instead of the console.log call, enable the date that was found in that record.
In theory, that should work. However, looking at the docs for Ext, I don't see a way to disable all dates, or to enable a date. You can only set which dates are disabled. But the general idea of updating the datepicker in that ondatesStoreLoad call is still what you should do.
You might need to extend the datepicker class, and add some custom methods to it to be able to enable a specific day.

Change the kendo calendar month names from shortform to fullform

In the kendo calendar control, the months names in the months view(where all the months of a specific year are listed) are shown in the short form instead of the full name. How can i change the names to full form only in this view. Ex: Mar instead of March.
I tried changing the date format using 'calendar.options.format' property, but it dosen't make any difference. Need help.
The calendar widget is programmed to always use the month abbreviation names. However, you can edit these names in the Kendo culture settings. Just be aware that they will change anywhere in Kendo that uses month abbreviations.
The abbreviations are stored in:
kendo.cultures.current.calendars.standard.months.namesAbbr
which is an array, indexed by the month. So you could set:
kendo.cultures.current.calendars.standard.months.namesAbbr[0] = "January";
kendo.cultures.current.calendars.standard.months.namesAbbr[1] = "February";
// ...etc...
Or, to make things easier, you can just copy the entire un-abbreviated months array to the abbreviated array, instead of setting each individual month:
kendo.cultures.current.calendars.standard.months.namesAbbr = kendo.cultures.current.calendars.standard.months.names;
However, that is still going to affect any other Kendo widgets that rely on the month abbreviations. A cleaner approach would be to make a custom culture for the Calendars to use. So in the initialization script for your page, after you include kendo.min.js, you can do this:
// just do this once on page load. copy current culture to a new one, and replace abbreviated months.
kendo.cultures.currentWithoutMonthAbbreviations = $.extend(true, {}, kendo.cultures.current);
kendo.cultures.currentWithoutMonthAbbreviations.name = "currentWithoutMonthAbbreviations";
kendo.cultures.currentWithoutMonthAbbreviations.calendars.standard.months.namesAbbr = kendo.cultures.currentWithoutMonthAbbreviations.calendars.standard.months.names;
Then the calendar widgets that you want to use full month names in, you can tell it to use your custom culture.
$("#datePicker").kendoDatePicker({
culture: "currentWithoutMonthAbbreviations"
});
You can do it with this script for days. I imagine the same would work for months:
var dayInfo = kendo.culture().calendar.days;
for (var i = 0; i < dayInfo.namesAbbr.length; i++) {
dayInfo.namesShort[i] = dayInfo.namesAbbr[i];
}

Resources