MVC - Manipulate Jquery plug in properties in ajax call - javascript

I am working with a Jquery time picker from http://labs.perifer.se/timedatepicker/
In the view I have this time picker control.
$("#startTime").timePicker({
startTime: "09.00",
endTime: new Date(0, 0, 0, 19, 0, 0),
show24Hours: false,
separator: '.',
step: 30
});
If a particular time (say 11:00 AM) is picked previously (and saved in db) that particular option should be disabled and not available for subsequent selections. In a MVC controller, via a service layer, I am getting a 'list' of all previously picked times.
public ActionResult DisableTimes(param1, param2)
{
List<string> listTimes = Webservice(param1,param2);
//getting previously saved times - above line
return Json(listTimes, JsonRequestBehavior.AllowGet);
}
I am making an ajax call in a java script function like this.. that passes the parameters to MVC controller and returns back the list of times.
$.ajax({
"url": "/ControllerName/DisableTimes/",
"type": "get",
"dataType": "json",
"data": { param1: $("#paramval1").val(), param2: $("#paramvalue2").val() },
"success": function (listTimes) {
//Code here - use the listTimes values and disable the
//appropriate timepicker drop down choices.
}
});
How can I make use of the list of times "listTimes" I am getting from controller to disable the Jquery Timepicker choices?

You should just be able to remove the li's from available options in the following manner:
$(listTimes).each(function() {
$('.time-picker').find('li:contains("' + this + '")').remove();
});
Edit:
It will be a little bit harder if you have multiple time pickers on a page though. You should be able to add the :first selector to only get the first time picker.
$('.time-picker:first').find('li:contains("' + this + '")').remove();
Live DEMO

apparently this datepicker plugin doesn't give you the possibility to remove his behavior.
But I do believe that you could remove the element from the document.
and re-add it again.
using :
http://api.jquery.com/remove/
and
http://api.jquery.com/add/
Or you could have two element for each time, show/hide what you need or using :
http://api.jquery.com/hide/
and
http://api.jquery.com/show/

it doesn't seem that the plugin offers that functionality by default. I would change these lines in the plugin code slightly (the bits where it appends to the list)
// Build the list
for(var i = 0; i < times.length; i++) {
$tpList.append("<li>" + times[i] + "</li>");
}
to something that adds some identifier to each li:
for(var i = 0; i < times.length; i++) {
$tpList.append("<li class='"+times[i]+'">" + times[i] + "</li>");
}`
just to make selecting those li elements easier then in your success handler, do something like:
"success": function (listTimes) {
$(listTimes).each(function(i,item){
$('li.'+item).remove();
});
//or may be if you are just getting an array of strings from the webservice then something like this will be enough: $('.'+listTimes.join(',.')).remove();
}
and also put the timepicker plugin call $("#startTime").timePicker inside the ajax success callback so that there is no race condition as the ajax callback will happen after the plugin initialization probably.
Another alternative is just to handle $('#startTime').change and check if the time is not allowed and display an error to the user.

Related

Struggling to call a Jscript function within jquery

I have a small MVC5/C# Web application. In short, users will select a location from a dropdown ("#UnitList"). This fires the jquery event, to populate the next dropdown ("#CheckItem") with a list of contacts associated to the location selected.
Being very inexperienced in Jscript and Jquery, I am lost.
Additionally, on the same event, I need to populate an element (hidden text box).
In order to fill the hidden elements, I use this code
$(function () {
$("[name='UnitList']").change(function () {
$("#DeliveryUnitID").val($(this).val());
});
});
To run the Jquery that populates the second dropdown:
$(document).ready(function() {
$("#UnitList").change(function() {
var batchId = $(this).val();
var urlForModesl = getURLBase() + "ICS_Requisitions/Details";
urlForModesl = urlForModesl + "/" + batchId;
var modelsHtml = "";
$('#CheckItem')
.find('option')
.remove()
.end()
.append('<option value="Select Contact"></option>')
.val('Contact')
$.ajax({
type: 'get',
url: urlForModesl,
contentType: 'application/json',
dataType: 'json',
success: function(jsonData) {
$.each(jsonData, function(key, value) {
modelsHtml += "<option value='" + value.LoginID + "'>" + value.ContactName + "</option>";
});
$("#CheckItem").html(modelsHtml);
$("#DeliveryUnitID").val($(this).val())
},
error: function(XMLHttpRequest, textStatus, errorThrown) {}
});
});
});
I am aware that I have two functions with the same name "$("#UnitList").change(function ()" and that this is very bad and causing conflicts. This is what I am trying to resolve.
I have tried to simply add the element update within the Jquery code, but that did not work.
I placed the following code
$("#DeliveryUnitID").val($(this).val())
Inside the Jquery, right after:
$("#CheckItem").html(modelsHtml);
But that does not work. The hidden elements are still empty.
I tried creating a function called foo, with the element update, and call that function from at the end of the jquery.
foo();
<script>
function foo() {
$("#DeliveryUnitID").val($(this).val());
}
That also left the element #DeliveryUnitID empty.
I know that I can't have two functions with the same name, but that's the only way I can get it working where the query populates the drop down, and then the hidden element is populated too. BUT . . . that's bad coding AND, for about 5% of the users, it fails.
I can't quite figure out how to make both happen with one onchange event.
It's been a while since I've used jQuery, so here's what I'm seeing:
On change Event:
Get the value of the #UnitList <select> (potential bug: these aren't being stored anywhere)
Clear the options
Re-populate with new ones from AJAX Request
Try to get value of new options (still within initial AJAX request, which might also be a bug? Like I said, it's been a while since I've used jQuery).
It looks like you might have a state-management issue?
Potential fixes:
Store values of first dropdown before you clear them.
Use the stored value to populate #DeliveryUnitID after the AJAX request
Use some if statements or remove the event listener to not constantly be running your code on change event once you get the data you need...unless you need it to be running constantly.
To me, it would seem beneficial (from a code pov and maybe also a UX perspective) to programmatically build a second dropdown to keep things clearer, but that might be overkill for what you're trying to accomplish.

$.fn.dataTableExt.aoFeatures.push change setting

I have below code
$.fn.dataTableExt.aoFeatures.push({
"fnInit": function (oSettings) {
oSettings.oScroll.sY = 5;
return { "oSettings": oSettings } ;
},
"cFeature": "T"
});
$.extend($.fn.dataTable.defaults, {
//"scrollY": 5,
"dom":"T"
});
I can see scrollY changed in function but no effect in datatable, How can overwrite the default setting using this function, since i have to put condition ono tableid,
otherwise I could have done below way which is working
$.extend($.fn.dataTable.defaults, {
"scrollY": 5,
});
I believe I am missing something on return statement which will override the things
fiddle reference
You code is not working for a few reasons. First, you are using an outdated API. $.fn.dataTableExt.aoFeatures.push is the old API used with $(...).dataTable(). By using $(...).DataTable() (note the capital "D") as you did in your fiddle, you are choosing to use the new API. (Read about converting code using the old API to use the new API here.) Using the current API is a great choice, but you then need to use $.fn.dataTable.ext.feature.push to set up your feature.
This works:
$.fn.dataTable.ext.feature.push({
"fnInit": function (settings) {
settings.oScroll.sY = 25;
},
"cFeature": "T"
});
However, the dom feature is intended to indicate the order of elements in the table. Using it to set style like scrollY is OK, but not exactly what they had in mind. The point being that if you are going to specify dom at all, you have to specify all the elements you want. In particular, you have to specify t for table or else the DataTable will not attach itself to the table at all. So you need to set up your table with something like this to trigger your scrollY "feature":
$(document).ready(function() {
var table = $('#example').DataTable({
"dom":"Tlftip"
});
Note that the order matters. The "T" has to come before the other elements that are affected by the changes made in the feature. "dom":"lftipT" will not have the desired effect.

fullcalendar: is there a way to call dayRender only after i load my events via events function

i'm using fullcalendar in a web application i"m building.
i load my events with events function and ajax.
here is my code:
var ajaxData;
var eventsJsonArray;
var json_backgrundColor;
var json_iconstring;
//alert('Hello! 1!');
$(document).ready(function () {
$('#calendar').fullCalendar({
header: {
left: 'prev',
center: 'title',
right: 'next,month,agendaWeek,agendaDay'
},
//custom events function to be called every time the view changes
events: function (start, end, timezone, callback) {
var mStart = start.format('M')
var yStart = start.format('YYYY')
$.ajax({
url: '$getMonthDataUrl',
type: 'GET',
data: {
startDate: start.format(),
endDate: end.format()
},
error: function () {
alert('there was an error while fetching events!');
},
success: function (data) {
alert('nice!!');
ajaxData = data;
json_iconstring = ajaxData['iconString'];
json_backgrundColor = ajaxData['Calendar_cell_background_color'];
eventsJsonArray = ajaxData['all_Events_For_The_Month'];
callback(eventsJsonArray); //pass the event data to fullCalendar via the supplied callback function
}
});
},
fixedWeekCount: false,
showNonCurrentDates: false,
dayRender: function (date, cell, view) {
console.log(json_backgrundColor);//this brings eror because json_backgrundColor is undefined
var cellDate = date.format('D');
if (date.format('M') == view.start.format('M')) //cheacking is this day is part of the currrent month (and not prev/next month)
{
alert(cellDate);
cell.css('background-color', json_backgrundColor[cellDate]);//this brings eror because json_backgrundColor is undefined
}
},
})
});
when i load my events via ajax i'm also getting the information about which background color each cell should get. i can only get this info via the events ajax request.
the problem is that when the dayRender is running, i still don't have the background color data. (json_backgrundColor is undefined).
is there a way that dayRender will run after the events calendar will stop running? or any other code that will fix my problem.
many thanks!!
Your problem is that the "dayRender" callback runs after the view is changed (changing the date using prev/next counts as changing the view, for this purpose), but before the events for the new view have been downloaded and rendered. That's why your json_backgrundColor array is undefined.
Since you mentioned that the colour to be used depends on the exact nature of the events currently scheduled for that specific day, we need to find something that we can run after all the events, and this colour data, have been downloaded.
Inspecting the HTML, we can see that the table cells used to draw each day all have the CSS class "fc-day" applied. They also have a data-date property containing the day that they relate to. Finally, days that are disabled (outside the main month, due to you setting showNonCurrentDates:false) have an extra class of "fc-disabled-day" applied. We can use these pieces of information to identify the cells we want to change, without having to use the dayRender callback.
The eventAfterAllRender callback runs once when all the events have been rendered. Therefore this seems like a good place to alter the background colours of the cells:
eventAfterAllRender(function(view) {
//loop through each non-disabled day cell
$('.fc-day:not(.fc-disabled-day)').each(function(index, element) {
//set the background colour of the cell from the json_backgroundColor arrray, based on the day number taken from the cell's "data-date" attribute.
$(this).css('background-color', json_backgroundColor[moment($(this).data("date")).format("D")]);
});
}
Note that I have renamed json_backgrundColor to json_backgroundColor to correct the spelling error.
N.B. This is brittle in the sense that it relies on the class names that fullCalendar uses internally to represent the day cells. If fullCalendar decides to do this differently in a future release, it will break (whereas if we were able to use the fullCalendar API via the designated callbacks, they would likely maintain consistency despite internal changes, or at least document any change). But it's pretty key to the Month view, so realistically it's not likely to change any time soon - you would just have to remember to test it if you update your fullCalendar version.
if anyone still wondering you can use dateSet option like
datesSet: event => {
var from = moment(event.start).format('YYYY-MM-DD');
var to = moment(event.end).format('YYYY-MM-DD');
dateStatus = getEachDateStatus(from, to);
//{'2022-11-10' : 'fullbooked', '2022-11-09' : 'halfBooked'};
Object.keys(dateStatus).forEach(key => {
$('td[data-date="'+key+'"]').addClass(dateStatus[key]);
});
},
Instead of relying on dayRender, you should create background color events based on your ajax:
events = [
...
{ date: date
color: ...
rendering: 'background'
className: 'my-class'
}]
You can transform events using css any way you like, with or without the rendering: 'background' option.

Ajax call in "for" loops skips odd/even iterations

If I am here asking it is because we are stuck on something that we do not know how to solve. I must admit, we already searched in StackOverflow and search engines about a solution.. but we didn't manage to implement it / solve the problem.
I am trying to create a JavaScript function that:
detects in my html page all the occurrences of an html tag: <alias>
replaces its content with the result of an Ajax call (sending the
content of the tag to the Ajax.php page) + localStorage management
at the end unwraps it from <alias> tag and leaves the content returned from ajax call
the only problem is that in both cases it skips some iterations.
We have made some researches and it seems that the "problem" is that Ajax is asynchronous, so it does not wait for the response before going on with the process. We even saw that "async: false" is not a good solution.
I leave the part of my script that is interested with some brief descriptions
// includes an icon in the page to display the correct change
function multilingual(msg,i) {
// code
}
// function to make an ajax call or a "cache call" if value is in localStorage for a variable
function sendRequest(o) {
console.log(o.variab+': running sendRequest function');
// check if value for that variable is stored and if stored for more than 1 hour
if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
console.log(o.variab+': value from localStorage');
// replace <alias> content with cached value
var cached = window.localStorage.getItem(o.variab);
elements[o.counter].innerHTML = cached;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(window.localStorage.getItem(o.variab),o.counter);
} else {
console.log(o.variab+': starting ajax call');
// not stored yet or older than a month
console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
$.ajax({
type: 'POST',
url: my_ajax_url,
data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
success: function(msg){
// ajax call, storing new value and expiration + replace <alias> inner html with new value
window.localStorage.setItem(o.variab, msg);
var content = window.localStorage.getItem(o.variab);
window.localStorage.setItem(o.variab+'_exp', +new Date);
console.log(o.variab+': replacement from ajax call');
elements[o.counter].innerHTML = content;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(msg,o.counter);
},
error: function(msg){
console.warn('an error occured during ajax call');
}
});
}
};
// loop for each <alias> element found
//initial settings
var elements = document.body.getElementsByTagName('alias'),
elem_n = elements.length,
counter = 0;
var i = 0;
for(; i < elem_n;i++) {
var flag = 0;
console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
sendRequest({
variab : elements[i].innerHTML,
api_key : settings.api_key,
language : default_lang,
counter : i
});
$(elements[i]).contents().unwrap().parent();
console.log(elements[i].innerHTML+': wrap removed');
}
I hope that some of you may provide me some valid solutions and/or examples, because we are stuck on this problem :(
From our test, when the value is from cache, the 1st/3rd/5th ... values are replaced correctly
when the value is from ajax the 2nd/4th .. values are replaced
Thanks in advance for your help :)
Your elements array is a live NodeList. When you unwrap things in those <alias> tags, the element disappears from the list. So, you're looking at element 0, and you do the ajax call, and then you get rid of the <alias> tag around the contents. At that instant, element[0] becomes what used to be element[1]. However, your loop increments i, so you skip the new element[0].
There's no reason to use .getElementsByTagName() anyway; you're using jQuery, so use it consistently:
var elements = $("alias");
That'll give you a jQuery object that will (mostly) work like an array, so the rest of your code won't have to change much, if at all.
To solve issues like this in the past, I've done something like the code below, you actually send the target along with the function running the AJAX call, and don't use any global variables because those may change as the for loop runs. Try passing in everything you'll use in the parameters of the function, including the target like I've done:
function loadContent(target, info) {
//ajax call
//on success replace target with new data;
}
$('alias').each(function(){
loadContent($(this), info)
});

FullCalendar - After initial load, dynamically updating ajax parameters not working

I'm working with http://arshaw.com/fullcalendar/ and I would like to dynamically filter the events shown based on various checkboxes on the page. I am using an ajax source (with filters passed as parameters) to gather data.
The problem I am running into is once I load the calendar, I cannot, for the life of me (or stackoverflow searches) figure out how to update the parameters. It seems once the calendar is loaded, those parameters are "baked" and cannot be changed.
I have tried every combination of addEventSource, removeEventSources, removeEvents, refetchEvents, etc (as recommended here: rerenderEvents / refetchEvents problem), with still no luck.
My current solution is to re-initiate the entire .fullCalendar every time a filter is updated-- this is leading to tons of issues as well and really isn't an elegant solution.
Any ideas on a simpler way to do this? Refetching your source with updated parameters each time should be automatic. I really do appreciate your help.
In my code i do like that :
I have an array with the calendars id to display and i update it when the user check or uncheck the checkbox.
In fullCalendar initialization I retrieve all events and i filter them with this function :
function fetchEvent( calendars, events) {
function eventCorrespond (element, index, array) {
return $.inArray(element.calendarid, calendars) > -1;
}
return events.filter(eventCorrespond);
}
$('#calendar').fullCalendar({
events: function(start, end, callback) {
//fetch events for date range on the server and retrieve an events array
//update calendars, your array of calendarsId
//return a filtered events array
callback(fetchEvent(calendars , events));
}
});
and when the user check or uncheck a checkbox i do :
$('#calendar').fullCalendar('refetchEvents');
The solution that works for me is:
$('#calendar').fullCalendar('removeEventSource', 'JsonResponse.ashx?technicans=' + technicians);
technicians = new_technicians_value;
$('#calendar').fullCalendar('addEventSource', 'JsonResponse.ashx?technicans=' + technicians);
After "addEventSource" events will be immediately fetched from the new source.
full answer here https://stackoverflow.com/a/36361544/5833265

Categories