JQuery Datatables and Bootstrap 3 datepicker - javascript

I'm using JQuery datatables to sort some table with data.
I'm using custom items to sort, in my case I have a select element which sorts one of the columns. And this works.
I also have 2 inputs that serve as datepickers.
These pickers have data formatted as same as on the table, so filtering works well, but my question is:
Is possible to filter column based on the range of pickers? So for example:
from 1 sep 2017 to 10 sep 2017?
I'm was looking for some custom function in datatables docs but I found nothing so it's why I'm asking StackOverflow community.
I think I need to check when second date one was selected and then get data of first datepicker and filter column based on this. But to make things easier, when the first picker is selected I will just show the second picker, so the user may know that selecting the first picker will trigger need of selecting the second one also....
$(document).ready(function() {
var table = $('#scroll-wrc-changes-table table').DataTable({
"paging": false,
});
var picker1 = $('#datetimepicker1').datetimepicker({
format: 'DD MMM YYYY',
defaultDate: new Date(),
});
var picker2 = $('#datetimepicker2').datetimepicker({
format: 'DD MMM YYYY',
defaultDate: new Date(),
});
picker1.on('dp.change',function() {
table.columns([3] ).search( this.value ).draw();
});
picker2.on('dp.change',function() {
table.columns([3] ).search( this.value ).draw();
});
// This is just select element
$('#table-select').change(function() {
table.columns([2] ).search( this.value ).draw();
})
});

Maybe this link can help you.
Range Filtering
The idea is to make function for custom filtering.
$.fn.dataTable.ext.search.push(
function( settings, data, dataIndex ) {
var date1 = new Date( $('#datetimepicker1').val() );
var date2 = new Date( $('#datetimepicker2').val() );
var dateData = new Date( data[3] ); // use data from the date column
if ( dateData >= date1 && dateData <= date2 )
{
return true;
}
return false;
});
Hope this help..

Asuming you are using ajax datatable . If not draw idea from this example
Add a row where you can set range for filter as:
<div class="col-md-3"> <label>From:</label> <input readonly="readonly" type="text" id="mindate" class="srchdp"> <i class="fa fa-times-circle-o" id="clear-mindate"></i></div>
<div class="col-md-3"> <label>To:</label> <input readonly="readonly" type="text" id="maxdate" class="srchdp"> <i class="fa fa-times-circle-o" id="clear-maxdate" ></i></div>
<div class="col-md-2"><button class="btn btn-primary" id="filter-record">Filter</button></div>
//initialize datepicker as
$("input:text.srchdp").datetimepicker({
changeMonth: true,
changeYear: true,
yearRange: "-100:+0",
dateFormat: 'mm/dd/yy',
controlType: 'select',
timeFormat: 'hh:mm:ss TT',
})
// now keep a event on filter button click
$(document).on("click", "#filter-record", function () {
assetListVM.search("").draw();
});
// now on ajax request
public ActionResult Get([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel, string mindate,string maxdate, string searchbase)
{
DataBaseEntities db = new DataBaseEntities();
IQueryable<Wishlist> query = db.Wishlists;
var totalCount = query.Count();
#region Filtering
// Apply filters for searching
var value = requestModel.Search.Value.Trim();
if (!string.IsNullOrEmpty(searchbase))
{
if (!string.IsNullOrEmpty(mindate) && !string.IsNullOrEmpty(maxdate))
{
DateTime datevaluemin;
DateTime datevaluemax;
var mindateval = DateTime.TryParse(mindate, out datevaluemin);
var maxdateval = DateTime.TryParse(mindate, out datevaluemax);
if (mindateval && maxdateval)
{
var minvalue = Convert.ToDateTime(mindate);
var maxvalue = Convert.ToDateTime(maxdate);
if (searchbase == "CreatedDate")
{
query = query.Where(p =>
p.CreatedDate >= minvalue
&& p.CreatedDate <= maxvalue);
}
}
}
else if (!string.IsNullOrEmpty(mindate))
{
DateTime datevalue;
var mindateval = DateTime.TryParse(mindate, out datevalue);
if (mindateval)
{
var minvalue = Convert.ToDateTime(mindate);
if (searchbase == "CreatedDate")
{
query = query.Where(p =>
p.CreatedDate >= minvalue
);
}
}
}
}
if (requestModel.Search.Value != string.Empty)
{
query = query.Where(p => p.Id.ToString().Equals(value) ||
p.ProductId.ToString().Equals(value) ||
p.MemberId.ToString().Contains(value)
);
}
var filteredCount = query.Count();
#endregion Filtering
#region Sorting
// Sorting
var sortedColumns = requestModel.Columns.GetSortedColumns();
var orderByString = String.Empty;
foreach (var column in sortedColumns)
{
orderByString += orderByString != String.Empty ? "," : "";
orderByString += (column.Data) + (column.SortDirection == Column.OrderDirection.Ascendant ? " asc" : " desc");
}
query = query.OrderBy(orderByString == string.Empty ? " asc" : orderByString);
#endregion Sorting
// Paging
query = query.Skip(requestModel.Start).Take(requestModel.Length);
var data = query.Select(asset => new
{
Id = asset.Id,
ProductId = asset.ProductId,
ProductName = asset.Product.ProductName,
MemberId=asset.MemberId,
CreatedDate = asset.CreatedDate.ToString(),
}).ToList();
return Json(new DataTablesResponse(requestModel.Draw, data, filteredCount, totalCount), JsonRequestBehavior.AllowGet);
}
}
}
this code is not complete hence it doesn't work alone.

Related

Highlighting multiple dates on jquery ui datepicker calendar works fine when clicking directly, but not when triggered by external button

I'm using the following to create a calendar that I can select multiple days for. It stores which days are turned "on" by using an object with values set to 1/0 true/false based on which days are selected.
Then I have a function that adds a "selected" class to each day that is turned on. It works flawlessly when I'm clicking dates manually, but I created buttons to select specific days (or date ranges later if I can get this working), but for some reason the code that highlights the days only works when clicking directly and not when using the buttons.
What the actual freck is going on?
<div id="days_cal_area">
<div id="days_cal"></div>
<div id="last_day" >Last</div>
</div>
<script>
// Maintain array of dates
var days = {};
$('#days_cal').datepicker({
inline: true,
firstDay: 0,
showOtherMonths: false,
selectOtherMonths: false,
dateFormat: 'yy-mm-dd',
changeYear: false,
defaultDate: new Date(1995, 0, 1),
onSelect: function (dateText, inst) {
day = parseInt(dateText.split('-')[2])
days[day] = !days[day];
daysStr();
},
beforeShowDay: function (date) {
var day = date.getDate();
if (days[day])
return [true, " date_selected day_"+day];
return [true, "day_"+day];
}
});
</script>
<div class="button_area row_items days_buttons">
<div class="sm_button" select="1" type="day">The 1st</div>
<div class="sm_button" select="15" type="day">The 15th</div>
<div class="sm_button" id='last_button'>Last day</div>
</div>
<div class="hidden_field">
<?php $task_form->write_fields(['days','weekdays','weeks','months']); ?>
</div>
<script>
function daysStr(){
console.log(days);
// Clear selected days
$('#days_cal .date_selected').removeClass('date_selected');
// Build a string for the form
temp = [];
$.each(days,function(day,addIt){
if (addIt) {
// Add it to the string for form submission
temp.push(day);
// Also mark it on the calendar
$('[data-day='+day+']').addClass('date_selected');
}
})
// Now add it to the form
$('#days_area [name=days]').val(temp.join(','));
}
$(document).ready(function(){
// prep the calendar (ONE TIMEM THINGS)
$('#days_area a').each(function(){
theTD = $(this).closest('td');
day = $(this).text();
$(theTD).data('day',day);
})
$('#days_area [type=day]').click(function(){
tempDays = $(this).attr('select').split(','); // Comma list of days
$(tempDays).each(function(index,day){
days[day] = true;
})
daysStr();
})
$('#last_button').click(function(){
$(this).toggleClass('on');
if ($(this).hasClass('on')){
$('#last_day').show();
days['last'] = true;
}
else {
$('#last_day').hide();
days['last'] = false;
}
daysStr();
})
})
</script>

How can I build a dataTable, with a dropbox filter on top, calculated on backend?

I need to change a dataTable to add a dropbox on top of it (not in the header) to filter it.
I have this column with dates like dd/mm/yyyy and I the year range does not go from 01/01/N to 31/12/N. It goes from 01/11/N to 31/10/N+1 and this rule will be used to calculate the filters available.
In case I have only this to lines :
-------------------------------------------------------
| date_header | header 2 | header 3 | header 4 |
|-------------------------------------------------------|
| 01/05/2013 | abc | qwe | xyz |
|-------------------------------------------------------|
| 05/11/2018 | hdf | ydb | lot |
-------------------------------------------------------
I should get the following results on de dropbox (respecting the rule I talked about) :
<2012/2013>
and
<2018/2019>
So, firstly, I need this dropbox to read every values presents on this column and calculate the filter values.
And then, filter the table using the range selected.
-- EDIT1 --
This is my initilialization script:
$element.DataTable({
"ajax": {
"url": this._tableDatasource,
"dataSrc": ""
},
"sDom": 'ltipr',
"bLengthChange": false,
"paging": this._detautNombreElementsPerPage > 0,
"pagingType": "full_numbers",
"iDisplayLength": this._detautNombreElementsPerPage,
"order": [[ this._defautColumnTrie, this._defautTypeTrie ]],
"columns": this._columns,
"columnDefs" : this._columnsProperties,
"fnRowCallback": function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
if ($(nRow).hasClass('even')) {
$(nRow).addClass("alt");
} else {
if ($(nRow).hasClass('alt')) {
$(nRow).removeClass("alt");
}
}
},
"fnDrawCallback": function() {
var pageCount = Math.ceil((this.fnSettings().fnRecordsDisplay()) / this.fnSettings()._iDisplayLength);
if (pageCount > 1) {
$('.dataTables_paginate').show();
} else {
$('.dataTables_paginate').hide();
}
},
"language": {
"sProcessing": "Chargement en cours...",
"sLengthMenu": "Montrer _MENU_ registres",
"sZeroRecords": "Aucun résultat n'a été trouvé",
"sEmptyTable": "Aucune donnée disponible pour ce tableau",
"sInfo": "_TOTAL_ éléments trouvés, affichage de _START_ à _END_",
"sInfoEmpty": "0 éléments trouvés, affichage de 0 à 0",
"sInfoFiltered": "(filtré au total de _MAX_ registres)",
"sInfoPostFix": "",
"sSearch": "Chercher:",
"sUrl": "",
"sInfoThousands": ",",
"sLoadingRecords": "Chargement en cours...",
"oPaginate": {
"sFirst": "Première page",
"sLast": "Dernière page",
"sNext": "Page suivante",
"sPrevious": "Page précédente"
}
},
"initComplete": function() {
if ($(this).attr('id') == "tableIndisponibilitesPassees") {
var dates = $('#tableIndisponibilitesPassees tr td:first-child').toArray();
populate_dropdown(dates);
//$('#tableIndisponibilitesPassees').dataTable().fnClearTable();
//$('#tableIndisponibilitesPassees').dataTable().fnFilter("20/10/2015 08:00:00").draw();
set_handler();
}
}
});
I had to add the initComplete to populate the table.
This is my populate dropdown :
function populate_dropdown(dates) {
// make an empty array variable to hold the list of saisons
var saisons = [];
// loop through the dates
for (var i = 0; i < dates.length; i++) {
var year = Number($(dates[i]).html().split(' ')[0].split('/')[2]);
var month = Number($(dates[i]).html().split(' ')[0].split('/')[1] - 1);
var day = Number($(dates[i]).html().split(' ')[0].split('/')[0]);
var datePFHA = new Date(year, month, day);
var dateDebutSaison = new Date(year, 10, 1);
// now let's calculate the season
var saison;
if (datePFHA < dateDebutSaison) {
saison = Number(year-1) + "/" + year;
} else {
saison = year + "/" + Number(year+1);
}
// now let's add that saison to the seasons array (if it's not already in the array!)
if ($.inArray(saison, saisons) == -1) {
saisons.push(saison);
}
}
// now that we're done looping through and building the seasons list, let's sort the array
saisons.sort();
// make a variable to hold all the <option> fields for the select dropdown
var options = "";
// loop through the years and make the options fields
$.each(saisons, function(key,value) {
options += "<option> Saison " + value + "</option>";
});
// take the new options string that we've built and put it inside the <select> dropdown
$('#filtre_saison').append(options);
}
And now I'm trying to set the handler like this :
function set_handler(dataTable) {
console.log("set_handler");
var filtre = $('#filtre_saison').on('change', function() {
// when someone changes the filter, get the beginning and ending of the season
var yearsSaison = $("#filtre_saison").val().split(' ')[1];
var debutSaison = new Date(yearsSaison.split('/')[0],10,01);
var finSaison = new Date(debutSaison.getFullYear() + 1, debutSaison.getMonth(), debutSaison.getDate());
console.log($('#tableIndisponibilitesPassees'));
console.log($('#tableIndisponibilitesPassees').dataTable());
console.log($('#tableIndisponibilitesPassees').dataTable().fnFilter("20/10/2015 08:00:00"));
console.log($('#tableIndisponibilitesPassees').dataTable().fnFilter("20/10/2015 08:00:00").draw());
$('#tableIndisponibilitesPassees').dataTable().fnFilter("20/10/2015 08:00:00").draw();
//$(dataTable).search("20/10/2015 08:00:00").draw();
//filter_table(debutSaison, finSaison);
});
}
I've tryed the search method on dataTable but it doesn't work. Return an error saying that search is not a function.
I've tryed with the fnFilter but now it returns an error in the draw function saying :
Cannot read property 'draw' of undefined
I've checked and after the fnFilter function, is returning undefined.
--- EDIT 2 ---
Almost forgot. This is my html code :
<select name="filtre_saison" id="filtre_saison">
</select>
Appreciate your help
OK, without any specifics of how the table is built, etc., a general way to go about this might be to use javascript/jQuery to loop through the date fields and build the year list. Then from that year list, you can populate a dropdown. Then you add a change handler to the dropdown and use javascript to show/hide elements based on the selected year.
Here's a quick and dirty example, which is assuming a couple things:
The fields that hold the date has a class (in my case, 'date_element')
The dates in the fields are of a consistent format
You can run the working snippet below to see it in action. And I added lots of code comments to explain what certain lines are doing.
Hope it helps! (and I hope I didn't just do your homework for you...).
// trigger the function that populates the dropdown when the page has finished loading, and then add a change handler on the dropdown
$(document).ready(function() {
populate_dropdown();
set_handler();
});
function populate_dropdown() {
// make an empty array variable to hold the list of years
var years = [];
// loop through the date_header fields (assuming that the elements have a class of date_element)
$('.date_element').each(function(){
// $(this) inside the each function refers to the <td class='date_element'> element
var this_date = $(this).html();
// get the year from the date. It would be better to use actual Date functions, but if the
// dates are consistent, we can just break them apart on the / characters and grab the last value
var this_year = Number(this_date.split('/')[2]);
// now let's add that year to the years array (if it's not already in the array!)
if ($.inArray(this_year, years) == -1) {
years.push(this_year)
}
});
// now that we're done looping through and building the year list, let's sort the array
years.sort();
// make a variable to hold all the <option> fields for the select dropdown
var options = "";
// loop through the years and make the options fields
$.each(years, function(key,value) {
options += "<option>" + value + "/" + Number(value+1) + "</option>";
});
// take the new options string that we've built and put it inside the <select> dropdown
$('#year_filter').append(options)
}
function set_handler() {
$('#year_filter').change(function() {
// when someone changes the filter, get the value of the first year
var selected_year = $("#year_filter").val().split('/')[0];
// make sure it's a number
if (!isNaN(selected_year)) {
filter_table(selected_year);
} else {
show_all_rows();
}
});
}
function filter_table(selected_year) {
//loop through the table rows, show ones that have the year and hide ones that don't have it
$('.date_element').each(function() {
if ($(this).html().indexOf(selected_year) == -1) {
//this row doesn't contain that year, let's hide the whole <tr>
$(this).parent().hide();
} else {
$(this).parent().show()
}
});
}
function show_all_rows() {
$('.date_element').each(function() {
$(this).parent().show();
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<form>
<select id="year_filter" name="year_filter"><option>Filter By Year</option></select>
</form>
<table>
<tr>
<th>date_header</th>
<th>header 1</th>
<th>header 2</th>
<th>header 3</th>
</tr>
<tr>
<td class='date_element'>01/05/2013</td>
<td>abc</td>
<td>qwe</td>
<td>xyz</td>
</tr>
<tr>
<td class='date_element'>05/11/2018</td>
<td>hdf</td>
<td>ydb</td>
<td>lot</td>
</tr>
</table>
Found the solution :
HTML :
<select name="filtre_saison" id="filtre_saison">
</select>
<table>
...
</table>
Javascript code :
"initComplete": function() {
if ($(this).attr('id') == "tableBuildings") {
var dates = $('#tableBuildings tr td:first-child').toArray();
populate_dropdown(dates);
$.fn.dataTable.ext.search.push( function( settings, data, dataIndex, rowData, counter ) {
if (settings.nTable.id === 'tableBuildings') {
//Calculation of beggining and ending of the room
var yearsBuildig = $("#filtre_saison").val().split(' ')[1];
var initialDate = new Date(yearsBuildig.split('/')[0],10,01);
var endDate = new Date(initialDate.getFullYear() + 1, initialDate.getMonth(), initialDate.getDate());
//Calculation of the Date object of the PFHA
var year = Number(rowData.initialDate.display.split(' ')[0].split('/')[2]);
var month = Number(rowData.initialDate.display.split(' ')[0].split('/')[1] - 1);
var day = Number(rowData.initialDate.display.split(' ')[0].split('/')[0]);
var hours = Number(rowData.initialDate.display.split(' ')[1].split(':')[2]);
var buildingDate = new Date(year, month, day);
if (buildingDate >= initialDate && buildingDate < endDate) {
return true;
} else {
//this row doesn't contain that year, let's hide the whole <tr>
return false;
}
} else {
return true;
}
});
$('#filtre_saison').on('change', function() {
table.draw();
});
table.draw();
}
}
function populate_dropdown(dates) {
// make an empty array variable to hold the list of building
var building = [];
// loop through the dates
for (var i = 0; i < dates.length; i++) {
var year = Number($(dates[i]).html().split(' ')[0].split('/')[2]);
var month = Number($(dates[i]).html().split(' ')[0].split('/')[1] - 1);
var day = Number($(dates[i]).html().split(' ')[0].split('/')[0]);
var buildingDate = new Date(year, month, day);
var initialDateRoom = new Date(year, 10, 1);
// now let's calculate the room
var room;
if (buildingDate < initialDateRoom) {
room = Number(year-1) + "/" + year;
} else {
room = year + "/" + Number(year+1);
}
// now let's add that room to the building array (if it's not already in the array!)
if ($.inArray(room, building) == -1) {
building.push(room);
}
}
// now that we're done looping through and building the building list, let's sort the array
building.sort();
// make a variable to hold all the <option> fields for the select dropdown
var options = "";
// loop through the years and make the options fields
$.each(building, function(key,value) {
options += "<option> room " + value + "</option>";
});
// take the new options string that we've built and put it inside the <select> dropdown
$('#filtre_saison').append(options);
}
Just added a function to populate the dropbox in the initComplete property to populate it only after the table is fully initialized (all the row values charged because I need to have different values depending on the values present on first column).
Then, I use the method to build my custom filter and then just redraw the table and Puff!
PS :
Needed to append this if :
if (settings.nTable.id === 'tableBuildings')
to check if it's the specific table I want because I have multiple tables on this page and the filter is applied to every datatable tables present in the page.
Thankyou #Reverend Pete

In MVC, how do I return items in and Entity database using a range of dates from Javascript Calendar

I want to get a range of items between dates from two JQuery calendars and then update the view when I press a submit button so that I only see the items between the selected dates. I'm not sure I'm going about things the best way.
My plan was to:
Get the user to select the dates in the calendars.
Use Javascript to return the dates as variables.
Send the variables to a controller which would then return a new view.
My code is below and my question is really in two parts.
Is there a better way to do this?
If this is ok, how can I get the javascript variables into the ActionLink to pass back to the controller?
Thanks in advance!
Controller:
// GET: Home
public ActionResult IndexDateRange(string sortOrder, DateTime startDateFromJS, DateTime endDateFromJS)
{
var sortedByDates = from pay in db.DailyPayments
select pay;
sortedByDates = sortedByDates.OrderByDescending(pay => pay.Date);
var first = sortedByDates.Select(pay => pay.Date).First();
var lastDate = sortedByDates.Select(pay => pay.Date).Last();
if (startDateFromJS > first.Date || (endDateFromJS < lastDate))
{
var dateRange = sortedByDates.Where(pay => pay.Date >= startDateFromJS && pay.Date <= endDateFromJS);
return View(dateRange.ToList());
}
return View(sortedByDates.ToList());
}
Javascript in the Index:
#Html.ActionLink("Get Dates", "IndexDateRange", routeValues: new { startDateFromJS = startDate, endDateFromJS = endDate })
<script>
$(function () {
var startDate = getStartDate();
var endDate = getEndDate();
function getStartDate() {
$('#startDate').datepicker();
$('#calendarSubmitButton').click(function () {
//var startDate = $('#startDate').datepicker('getDate');
var startDate = $('#startDate').datepicker('getDate');
console.log(startDate);
return startDate;
})
};
function getEndDate() {
$('#endDate').datepicker();
$('#calendarSubmitButton').click(function () {
var endDate = $('#endDate').datepicker('getDate');
console.log(endDate);
return endDate;
})
};
Temporary Test JS to try and wire up the href. When I click on it, it just adds the pound symbol to the home/index Url and in the browser developer tools it says illegal character.
Get Dates
<script type="text/javascript">
$('#calendarSubmitButton').click(function() {
var tempStartDate = #DateTime.Now.AddMonths(-1).ToString("yyyyMMdd");
var tempEndDate = #DateTime.Now.ToString("yyyyMMdd");
location.href='#Url.Action("IndexDateRange")+'?startDateFrom‌​JS='+$('tempStartDate')+'&endDateFromJS='+$('tempEndDate')';
});
</script>
Screen Grab:
Screenshot of the setup
Try this
Get Dates
<script type="text/javascript">
$('#calendarSubmitButton').click(function() {
var tempStartDate = '#DateTime.Now.AddMonths(-1).ToString("yyyyMMdd")';
var tempEndDate = '#DateTime.Now.ToString("yyyyMMdd")';
location.href='#Url.Action("IndexDateRange")?startDateFrom‌​JS='+tempStartDate +'&endDateFromJS='+tempEndDate;
});
</script>
Thanks to the help of #StephenMuecke and #Tanmay, I was finally able to get this to work. I'm posting the functioning code here.
Controller
// GET: Home
public ActionResult Index(string sortOrder, string startDate, string endDateFromJS)
{
var sortedByDates = from pay in db.DailyPayments
select pay;
sortedByDates = sortedByDates.OrderByDescending(pay => pay.Date);
if (startDate != null && endDateFromJS != null)
{
DateTime convertedStartDateFromJS = DateTime.ParseExact(startDate, "yyyyMMdd", new CultureInfo("en-US"));
DateTime convertedEndDateFromJS = DateTime.ParseExact(endDateFromJS, "yyyyMMdd", new CultureInfo("en-US"));
var dateRange = sortedByDates.Where(pay => pay.Date >= convertedStartDateFromJS && pay.Date <= convertedEndDateFromJS);
return View(dateRange.ToList());
}
return View(sortedByDates.ToList());
}
Javascript and HTML in the index.cshtml
<div class="form-group">
#Html.Label("Total payment:", new { id = "totalTextbox" }) <br />
#Html.TextBox("Total", Math.Floor(totalPayment) + " yen" , new { #class = "alert alert-danger", #readonly = "readonly" })
</div>
<div class="form-group">
#Html.Label("Starting Date:")
#Html.TextBox("Starting Date:", "", new { #class = "date-picker", id = "startDate" })
#Html.Label("Ending Date:")
#Html.TextBox("Ending Date:", "", new { #class = "date-picker", id = "endDate" })
#*<input type="submit" href="#" id="calendarSubmitButton" class="btn btn-primary" />*#
Get Dates
<script type="text/javascript">
$(document).ready(function () {
$('#calendarSubmitButton').click(function () {
//TODO: Figure this out.
var tempStartDate = $("#startDate").val($.datepicker.formatDate('yymmdd', new Date($('#startDate').datepicker('getDate'))));
var tempEndDate = $("#endDate").val($.datepicker.formatDate('yymmdd', new Date($('#startDate').datepicker('getDate'))));
location.href = '#Url.Action("Index")?startDate=' + tempStartDate.val() + '&endDateFromJS=' + tempEndDate.val();
})
});
</script>
</div>

Bootstrap Datepicker and Disable C#/JSON array of dates,

I have a list of dates that I want to disable in my bootstrap date picker. I cannot get the datesDisabled function to work with the array of dates returned from JSON. It does work with a hard coded array of dates.
Is there something that I need to do format the dates returned from JSON in order to get it to work?
Query:
var DatesBooked= JsonConvert.SerializeObject(db.Calendar.Where(x => x.CalLocation != "OFF")).Select(x => x.CalDate).Distinct().ToList());
In my view:
#Html.TextBox("AddedDates", null, new { #class = "form-control small", #Value = ViewBag.SelDate, autocomplete = "off" })
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Scripts/jquery.timepicker.js"></script>
<script src="~/Scripts/bootstrap-datepicker.min.js"></script>
<script>
var unavailableDates= #Html.Raw(Json.Encode(Model.DatesBooked));
$input = $("#AddedDates");
$input.datepicker({
multidate: true,
multidateSeparator: ',',
datesDisabled: unavailableDates,
});
</script>
unavailableDates value
var unavailableDates = "[\"2016-05-01T00:00:00\",\"2016-05-02T00:00:00\",\"2016-05-03T00:00:00\",\"2016-06-24T00:00:00\",\"2016-06-25T00:00:00\"]"
If I hardcode thisfor unavailableDates, everything works fine.
var unavailableDates = ["05/25/2016", "05/26/2016"]
How do I need to format the dates in order to get this to work?
TIA!
Well after many attempts and more research, I was able to solve this by doing the following:
I reformatted the date using C#:
var checkdates = db.Calendar.Where(x => x.CalLocation != "OFF")).Select(x => x.CalDate).Distinct().ToList()
var DatesBooked= JsonConvert.SerializeObject(checkdates, Formatting.None, new IsoDateTimeConverter() { DateTimeFormat = "MM/dd/yyyy" });
Then in the view, I stripped the "\" characters returned by JSON and created an array:
var unavailableDates = #Html.Raw(Json.Encode(Model.DatesBooked));
var formatDates = unavailableDates.replace(/\\/g, "");
var trimDate = formatDates.slice(1, -1); // to remove " at beginning and end
var finalDates = JSON.parse("[" + trimDate + "]");
$input = $("#AddedDates");
$input.datepicker({
multidate: true,
multidateSeparator: ',',
datesDisabled: finalDates,
todayHighlight: true
});

knockout mvvm binding with metro.js datepicker

I was trying to hack my way around with the metro.js datepicker and knockout. So far my datepicker binding code looks like:
ko.bindingHandlers.datepicker = {
init: function(el, va, ba, model, ctx) {
var prop = va();
$(el).datepicker({
onSelect: function(txt, date) {
prop(date);
}
});
},
update: function(el, va, ba, model, ctx) {
var prop = va();
var date = ko.unwrap(prop);
if(date) {
applyDate(date);
}
function applyDate(dt) {
var j = $(el);
var dp = j.data('datepicker');
var inp = j.find('input');
var fmt = dp.options.format;
var sDate = format(fmt, dt);
// dp._calendar.calendar.dayClick(sDate, dt);
// inp.value = sDate;
dp._calendar.calendar('setDate', sDate);
j.find('input').val(dp._calendar.calendar('getDate')).trigger('change', sDate);
}
function format(fmt, dt) {
fmt = fmt.replace('yyyy', dt.getFullYear());
fmt = fmt.replace('mm', pad(dt.getMonth() + 1));
fmt = fmt.replace('dd', pad(dt.getDate()));
return fmt;
}
function pad(n) {
return parseInt(n) < 10 ? '0' + n: '' + n;
};
}
}
Issue is that when I issue a model update on the date property its bound to the datepicker doesn't update. I mean, it does it the very first time, but post that, it fails to update the textbox; calendar shows okay however. Ultimately I need to change the logic in the applyDate function...
JSBin: http://jsbin.com/rupaqolexa/1/edit?html,js,output
Update: Another issue just cropped up...it doesn't work in IE 10+. The date appears as NaN in the UI...
Update: Steps for reproduction
type date 2nd text box: 2013/05/13 & click on the Change button. Observe date is updated in the datepicker textbox. This works as expected. (Except in IE).
type another date in the textbox & click the change button. Observe the date is not updated in the datepicker textbox. Expected here that the datepicker textbox updates with latest value.
In the update part of your custom binding you need to make all the changes to the bound elements, which include the calendar widget, and the related input element.
I've modified the code to do so, so that it now works.
function ViewModel(date) {
var model = this;
model.date = ko.observable(date);
model.set = function() {
var val = $('#somedate').val();
var dt = new Date(val);
model.date(dt);
};
}
ko.bindingHandlers.datepicker = {
init: function(el, va, ba, model, ctx) {
var prop = va();
$(el).datepicker({
onSelect: function(txt, date) {
prop(date);
}
});
},
update: function(el, va, ba, model, ctx) {
var newDate = ko.unwrap(va());
if(newDate) {
var $el = $(el);
var datePicker = $el.data('datepicker');
var $input = $el.find('input');
var formattedDate = format(datePicker.options.format, newDate);
datePicker._calendar.calendar('setDate', formattedDate);
$input.val(formattedDate);
//$input.val(dp._calendar.calendar('getDate'))
// .trigger('change', sDate);
}
function format(fmt, dt) {
fmt = fmt.replace('yyyy', dt.getFullYear());
fmt = fmt.replace('mm', pad(dt.getMonth() + 1));
fmt = fmt.replace('dd', pad(dt.getDate()));
return fmt;
}
function pad(n) {
return parseInt(n) < 10 ? '0' + n: '' + n;
}
}
};
var m = new ViewModel();
$(function(){
ko.applyBindings(m);
});
<link href="//metroui.org.ua/css/metro.css" rel="stylesheet">
<link href="//metroui.org.ua/css/metro-icons.css" rel="stylesheet">
<link href="//metroui.org.ua/css/metro-responsive.css" rel="stylesheet">
<link href="http://metroui.org.ua/css/metro-schemes.css" rel="stylesheet">
<script src="http://metroui.org.ua/js/jquery-2.1.3.min.js"></script>
<script src="http://metroui.org.ua/js/metro.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-debug.js"></script>
<div>
<div class="input-control text" data-bind="datepicker: date">
<input type="text">
<button class="button"><span class="mif-calendar"></span></button>
</div>
</div>
<div>
<label>Date</label>
<div class="input-control text">
<input type="text" id="somedate"/>
</div>
<input type="button" class="button" value="Change" data-bind="click: set"/>
</div>
<div>
<code data-bind="text: date"></code>
</div>
However there is still a little hiccup: the datepiceker's calendar setdate adss new selected date, instead of replacing selected ones. Please, see the API docs to solve this yourself.

Categories

Resources