I do apologize if this is an easy fix, I'm a tad new to jquery. To start I don't think that it is my initial call that is messing up because if I put a simple alert function in than it will work fine onclick, basically when this <li> is clicked on, jquery trigers an ajax to php function sending the class of the <li> to a php script and back, opening an alert with the result. As far as I can tell it should be working, but again my knowledge is rather limited. Any change anyone can take a look at what I have and see if you can clean it up at all, currently nothing happens onclick, no errors even appear in the console. But I imagine that even my ajax call is wrong. Any ideas why nothing happens on click?
HTML:
<li title = "Previous Month" id = "changeMonthBack" class = "<?php echo date('n'); ?>"><img src="images/leftArrow.gif" width="54" height="45" alt="previous month"></li>
jQuery/javascript:
//javascript document
$(document).ready(function(){
//need to do an onclick for getting the new month(previous)
$(".changeMonthBack").click(function(){
function calendar(){
//set the id for php
var identifier = 1;
//get the class to use for month
var str = document.getElementById("changeMonthBack").class;
//get the month number
//if the month is 1, we obviously need it to be 12
if str == 1{
var month = 12;
}
else{
var month = str - 1;
}
$.post("redraw.php"),{
identifier: identifier,
month: month
},
function(data,status){
alert("Data: " + data + "\nStatus: " + status);
};
})//end function 1
});
There are multiple problems with the script.
1. As Aesthete suggested the selector should be an id selector #changeMonthBack
2. You are creating a closure method called calendar but never called it
3. There were multiple syntax error (Use a javascript editor like spket)
You are creating a function called calendar but never calls it.
$(document).ready(function() {
// need to do an onclick for getting the new month(previous)
$("#changeMonthBack").click(function() {
// set the id for php
var identifier = 1;
// get the class to use for month
var str = parseInt($(this).attr('class'),10);
// get the month number
// if the month is 1, we obviously need it to be 12
if (str == 1) {
var month = 12;
} else {
var month = str - 1;
}
$.post("redraw.php", {
identifier : identifier,
month : month
},
function(data, status) {
alert("Data: " + data + "\nStatus: "
+ status);
});
});
});
Related
I used dhtmlx for chart gantt, I succeed in saving tasks in the data base, the problem is that when I add a new task there is no change in the chart,
for example if I add a new task with 4 days as duration it appears just one cell not four ones and also for the other properties.
Here the code of adding a new task :
<script type="text/javascript">
gantt.init("gantt_here");
gantt.attachEvent("onLightboxSave", function(id, task, is_new){
mnth = ("0" + (task.start_date.getMonth()+1)).slice(-2),
day = ("0" + task.start_date.getDate()).slice(-2);
mnth = ("0" + (task.end_date.getMonth()+1)).slice(-2),
day = ("0" + task.end_date.getDate()).slice(-2);
$.post("Control",{id:task.id,duration:task.duration,text:task.text,start_date:[ day,mnth, task.start_date.getFullYear() ].join("-").toString()},function(data){
alert(data);
}) ;
gantt.hideLightbox();
});
</script>
Try returning 'true' from onLightboxSave handler http://docs.dhtmlx.com/gantt/api__gantt_onlightboxsave_event.html
If you return 'false' or 'undefined' (as in your case), the form stays opened and the form values are not applied to the client-side.
Returning 'true' will save values and close the form, so you won't need to call hideLightbox manually
gantt.attachEvent("onLightboxSave", function(id, task, is_new){
var dateToStr = gantt.date.date_to_str("%d-%m-%Y");
$.post("Control",{
id:task.id,
duration:task.duration,
text:task.text,
start_date:dateToStr(task.start_date)
},function(data){
alert(data);
}) ;
return true;
});
I am trying to write a custom datepicker, where the default drop downs for months and year ranges (enabled through changeMonth and changeYear options) are replaced by custom drop downs. It is something like this:
Fiddle: http://jsfiddle.net/gGV3v/
$("#myId").datepicker({
...default settings...
beforeShow: function() {
...here I replace the default dropdowns by custom dropdowns...
...something like...
$(".ui-datepicker-month").replaceWith("#custom-html-block");
$(".ui-datepicker-year").replaceWith("#another-custom-html-block");
}
});
On choosing either month or year from the custom dropdowns, I want to change the date in the view accordingly. So I construct the date string from the current month and year (the date for the new month/year combo defaults to 1 here), and I call
$("#custom-html-block .custom-dropdown-option").on("click",function() {
...construct newDateString...
$("#myId").datepicker("setDate",newDateString)
});
$("#another-custom-html-block .custom-dropdown-option").on("click",function() {
...construct newDateString...
$("#myId").datepicker("setDate",newDateString)
});
I want the span with text foo to remain intact when setting the new date programmatically on clicking it.
The problem is: it wipes off the custom drop downs and the default ones come again. I tried to do things like this:
$("#myId").datepicker($.extend({setDate: newDateString},oldSettings))
But it still doesn't work. How do I make this work?
You can set the value of the function $.datepicker._generateMonthYearHeader, the downside it that will be global for all datepicker in the page.
The sample is below:
$.datepicker._generateMonthYearHeader = function(inst, drawMonth, drawYear, minDate, maxDate,
secondary, monthNames, monthNamesShort) {
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
changeMonth = this._get(inst, "changeMonth"),
changeYear = this._get(inst, "changeYear"),
showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
html = "<div class='ui-datepicker-title'>",
monthHtml = "";
// year selection
if ( !inst.yearshtml ) {
inst.yearshtml = "";
if (secondary || !changeYear) {
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
} else {
// determine range of years to display
years = this._get(inst, "yearRange").split(":");
thisYear = new Date().getFullYear();
determineYear = function(value) {
var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
parseInt(value, 10)));
return (isNaN(year) ? thisYear : year);
};
year = determineYear(years[0]);
endYear = Math.max(year, determineYear(years[1] || ""));
year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
inst.yearshtml += "<span class = 'dummy'>Foo</span> <select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"
for (; year <= endYear; year++) {
inst.yearshtml += "<option value='" + year + "'" +
(year === drawYear ? " selected='selected'" : "") +
">" + year + "</option>";
}
inst.yearshtml += "</select>";
html += inst.yearshtml;
inst.yearshtml = null;
}
}
And your fiddle: http://jsfiddle.net/gGV3v/2/
UPDATE:
Without the buttons, and using a better approach, now you have control of all generated HTML:
var oldGenerateHTML = $.datepicker._generateHTML;
function newGenerateHTML(inst) {
var html = oldGenerateHTML.call(this, inst);
var $html = $(html);
$html.find('[data-handler=prev]').remove();
$html.find('[data-handler=next]').remove();
$html.find('[data-handler=selectMonth]').replaceWith('<span class="dummy">Foo</span>');
return $html;
}
$.datepicker._generateHTML = newGenerateHTML;
Fiddle also updated: http://jsfiddle.net/gGV3v/4/
In general this is why extend sucks. The parent (in your case datepicker) doesn't know anything about childs (your custom html). Everytime it refresh the view, your changes are lost. This problem is usually solved using composition. The goal is to create your own widget (I think that was the term in jQuery) that have datepicker as a local variable and to control _generateMonthYearHeader function calls. It's easy to say in theory but in practice (specially case with jQuery) is hard to achive. Easier solution will be to proxy the function.
//preserve _generateHTML because after it finish, html is visible and .ui-datepicker-month and .ui-datepicker-year are in dom tree
fn = $.datepicker._generateHTML; //preserve original function
$.datepicker._generateHTML = function(inst) {
//call original function
fn.call(this, inst);
//do custom changes
//you'll need better selectors in case of multiple datepicker instances
$(".ui-datepicker-month").replaceWith("#custom-html-block");
$(".ui-datepicker-year").replaceWith("#another-custom-html-block");
}
Personally I dislike this approach (I prefer composition as I said) but in your case it'll be easier to implement. The reason its easier is because generateMonthYearHeader is called from many different functions.
P.S. Not tested
HTML input fields
<input type="text" name="partner_name_or_description[]" id="partner_name_or_description1" class="row_changed1"/>
<input type="text" name="partner_name_or_description[]" id="partner_name_or_description2" class="row_changed2"/>
<input type="text" name="partner_name_or_description[]" id="partner_name_or_description3" class="row_changed3"/>
Part of jquery autocomplete code (that works)
$("#partner_name_or_description1:input, #partner_name_or_description2:input, #partner_name_or_description3:input").autocomplete(
"__autocomplete_source.php",
In jquery there are: partner_name_or_description1, 2, 3 etc.... Instead of this long list of 1, 2, 3 etc. want to use something short with serialize (or in other possible way).
At first get these 1,2,3... with this code
$('[id^="partner_name_or_description"]').each(function (index, partner_name_or_description) {
var s_id = partner_name_or_description.id.substring(27);
});
Then instead of that long list trying to make something like this
$("#partner_name_or_description" + s_id + " :input").serialize().autocomplete(
It does not work. If View source, see
$("#partner_name_or_description" + s_id + " :input").serialize().autocomplete(
Do not understand reason... May be incorrectly use serialize().autocomplete
Or may be must not use serialize() and must use something else.
I can not use class="row_changedX" because it is necessary for other purposes (class must be like row_changed1, 2, 3; for each row class name must be different).
Working code
/*Actually do not understand why this is necessary, but if I delete all uncommented, then code does not work*/
function findValue(li) {
/*if( li == null ) return alert("No match!");
// if coming from an AJAX call, let's use the CityId as the value
if( !!li.extra ) var sValue = li.extra[0];
// otherwise, let's just display the value in the text box
else var sValue = li.selectValue;
alert("The value you selected was: " + sValue);*/
}
function selectItem(li) {
findValue(li);
}
function formatItem(row) {
return row[0] + " (id: " + row[1] + ")";
}
$('[id^="partner_name_or_description"]').autocomplete("__autocomplete_source.php",
{
delay:10,
minChars:2,
matchSubset:1,
matchContains:1,
cacheLength:10,
onItemSelect:selectItem,
onFindValue:findValue,
formatItem:formatItem,
autoFill:true
}//{ delay:10,
)//.autocomplete(;
Edit: Thanks to #jk -- this will work:
$('[id^="partner_name_or_description"]').autocomplete(
"__autocomplete_source.php",
//do stuff
});
I'm building out an online reservation system for a pet-boarding business in my city and I've hit a wall as to how to efficiently carry out this specific functionality.
Quick gist of the user process...
Some preliminary info is given (client info, pet info, etc etc).
User chooses 2 dates; the check-in and check-out days.
The program calculates the number of days the client is staying and each day is thrown into a constructor for class "Day". A ... block is generated for each day and displayed to the user. It also might be worth noting that all of the Day objects are stored in an array which is then contained in the mama class "ReservationData"...which besides the Day-array also holds some meta-data pertaining to the reservation itself.
Anyway, my problem is that once the 'dayBlocks' are listed & displayed to the user, the user must then be able to go and check individual "extras" that they want for their pet on that specific day.
So I've broken it down so that {ReservationData} <--(has an array of)-- {Days} <--(has an array of)-- {Extras}. There are 14 extra services to choose from, so for each day displayed there is a simple list of checkboxes and labels.
Ideally, I want it setup so that when a checkbox is checked by the user, it directly & immediately alters its corresponding variable within the reservationDataDaysExtraDeepArray accordingly. The C-programmer in me wants to tie a pointer to each checkbox, but I'm (at least I think) pretty sure that's not doable with jQuery.
Although I think I explained it pretty clearly, here's some of the code:
//Day Object/Class
function day(_date, _daynum) {
this.date = new Date(_date);
this.dayNum = _daynum;
this.dayExtras = {
'YH': false, //<--- How can I directly manipulate
'PP': false, //<--- all of these guys via user-control
'EE': false, //<--- of corresponding/assigned
'ST': false, //<--- checkboxes?
'PT': false,
'TT15': false,
'TT30': false,
'TT45': false,
'DC': false //--- Or can I? :/
};
console.log("Day object created with date of " + day.date + " and day-number of " + day.dayNum + ".");
this.getDayNum = function() { return this.dayNum; }
this.getDayDate = function() { return this.date; }
}
This is my first question on this site, but I did a lot of searching and am still lost...thanks guys!
Assuming the name of your checkboxes correspond to the keys in your dayExtras object something like this would do..
//Day Object/Class
function day(_date, _daynum) {
this.date = new Date(_date);
this.dayNum = _daynum;
this.dayExtras = {
'YH': false, //<--- How can I directly manipulate
'PP': false, //<--- all of these guys via user-control
'EE': false, //<--- of corresponding/assigned
'ST': false, //<--- checkboxes?
'PT': false,
'TT15': false,
'TT30': false,
'TT45': false,
'DC': false //--- Or can I? :/
};
console.log("Day object created with date of " + day.date + " and day-number of "+day.dayNum+".");
this.getDayNum = function() { return this.dayNum; }
this.getDayDate = function() { return this.date; }
this.setDayExtras = function (key,val) {
if(key in this.dayExtras){
this.dayExtras[key] = val;
}
}
}
var myDay = new day(null,null);
$(document).on('change','#myForm input[type="checkbox"]', function () {
myDay.setDayExtras(this.name,this.checked);
});
Got it working, thanks for pointing me in the right direction guys!
function saveExtra(me) {
var extraName = me.attr('name');
var extraVal = me.val();
(reservationData[extraName]).dayExtras[extraVal] = me.prop('checked');
for (key in reservationData) {
(reservationData[key]).dump(); //Day data-dump method.
}
}
this.generateExtrasGrid = function() {
var fieldName = "day" + this.dayNum + "";
var exGrid = "";
exGrid += "<form class='extrasGrid' id='" + this.dayNum + "'>";
exGrid += "<input type='checkbox' class='extra' name='" + fieldName + "' value='YH' onclick='saveExtra($(this))' />";............
exGrid += "</form>";
return exGrid;
}
Below is a function where it controls whatever happens after a file has finished uploading in its own table row. Each table row consists of a file input where the user can upload a file and then the name of the file is appended within it's own table row.
If the upload was successful then it displays a successful message, if upload was not successful then it displays a message stating there is an error. But I also have another function within the function where the user can delete a file by clicking on the "Delete" button. The only problem I have is with this line of code:
$(".imagemsg" + counter).html(data);
Let's say that I have 2 table rows, and I delete a file in the first row, the message within .imagemsg should only be displayed in the first row as that was the row the deletion occured, it shouldn't display the message in the first and second row.
Another example is that if I have 4 table rows and I delete the file in the third row, then the message should be displayed in the 3rd row as that is where the deletion has occured.
So my question is what do I need to add to $(".imagemsg" + counter).html(data); so that the message is only displayed within the row the deletion of the file occured and not in all .imagemsg which is in every row?
Below is full code:
function stopImageUpload(success, imagefilename){
var result = '';
var counter = 0;
counter++;
if (success == 1){
result = '<span class="imagemsg'+counter+'">The file was uploaded successfully!</span><br/><br/>';
$('.listImage').eq(window.lastUploadImageIndex).append('<div>' + htmlEncode(imagefilename) + '<button type="button" class="deletefileimage" image_file_name="' + imagefilename + '">Remove</button><br/><hr/></div>');
}
else {
result = '<span class="imageemsg">There was an error during file upload!</span><br/><br/>';
}
$(".deletefileimage").on("click", function(event) {
var image_file_name = $(this).attr('image_file_name');
jQuery.ajax("deleteimage.php?imagefilename=" + image_file_name)
.done(function(data) {
$(".imagemsg" + counter).html(data);
});
$(this).parent().remove();
});
return true;
}
BELOW IS HTML CODE:
var $fileImage = $("<form action='imageupload.php' method='post' enctype='multipart/form-data' target='upload_target' onsubmit='return imageClickHandler(this);' class='imageuploadform' >" +
"Image File: <input name='fileImage' type='file' class='fileImage' /></label><br/><br/><label class='imagelbl'>" +
"<input type='submit' name='submitImageBtn' class='sbtnimage' value='Upload' /></label>" +
"</p><p class='listImage' align='left'></p>" +
"<iframe class='upload_target' name='upload_target' src='#' style='width:0;height:0;border:0px;solid;#fff;'></iframe></form>");
I believe that your counter variable will always be 1. So, all your span.imagemsg1 are the same. This is why you get the message in every row. Set the counter outside the function to increment the counter.
I believe that will stop the behavior that you are seeing, but I would like to give a shout out to the other answers as they are giving good advice to cleaning this code up.
Frankly, you should never use unique identifier in the class. Why not use an id or a data-image-count attribute?
In your html code you'll need to add a unique identifier, I would suggest using id. This way when you try to reference the element to add the error message in, it will only find one element. Currently it's looking for the first occurrence of the element with class = "imagemsg". You'll need a way to loop through each "row" and make the id's "imagemgs1", "imagemsg2", etc...Hope it helps.
It would be helpful to be able to see the HTML. Also, I cannot see in your script what you do with the "result" value. At this stage, I personally don't think there is enough info to help satisfactorily you yet.
However, an issue you will undoubtedly see is with your "counter" variable. Maybe that is your problem - hard to tell without the detail I asked for above. Your jQuery.ajax call will complete at some point but the value of "counter" may not be the same as when you called the jQuery.ajax() method. This is because the "counter" variable is being declared in a different scope.
E.g. Look at the code below. It sort of demonstrates your problem with the counter variable. It may look like at the end of 5 seconds it will spit out the numbers from 1 to 10 but it won't. It will spit out the value "10" ten times.
var x = 0;
for (var i = 0; i < 10; i++)
{
x++;
setTimeout(function() { console.log(x); }, 5000);
}
This problem applies to your code as well. You can fix the above by copying the variable value in to a variable of your local scope. E.g.:
var x = 0;
for (var i = 0; i < 10; i++)
{
var newScope = function() {
x++;
var y = x;
setTimeout(function() { console.log(y); }, 5000);
}();
}