I am working on a WP plugin for a client that communicates with UPS, USPS and FEDEX. USPS requires multiple steps so I am using a UI Dialog Modal in which I add content dynamically via AJAX (PHP). The content is great, but it seems that when I click the continue button on the first dialog it fires all successive dialog button functions. I have a function that I call to change dialog content, and each calling function sends AJAX data and sets the options for the next dialog. I need the button to simply complete its function and allow the user to make selections on the next dialog. While I have been using JQuery, JS and PHP for quite sometime I am fairly new to jQuery UI. Please see my code below for reference. Any help on this would be greatly appreciated.
"obj" is an object returned from PHP containing shippment data and html for dialog.
Function for updating dialog content
show_dialog = function( title, html, options ) {
$( "#dialog" ).dialog({
autoOpen: false,
});
$('#dialog').html( html );
$('#dialog').dialog( 'option', 'title', title );
$('#dialog').dialog( options );
$('div.ui-dialog-buttonset button.ui-button span.ui-button-text').each(function() {
$(this).html($(this).parent().attr('text'));})
}
Function for address validation
usps_address_check = function( obj ) {
if( obj.VStatus === 'AddressMatch' ) {
var title = obj.Title;
var options = {
resizable: false,
width:800,
modal:true,
buttons: {
//when this button is clicked it fires the function in the next dialog below process shipment.
'Continue': function(event) {
if( $('#verified').attr('checked') ) {
data = {
action: 'usps_ajax',
call: 'check_rate',
post: $('#post_id').val(),
};
ajax_request( data );
} else {
$(this).dialog( 'option', 'title', "Please click the checkbox to confirm corrected address..." );
}
},
Cancel: function() {
$(this).dialog( 'close' );
}
}
}
}
show_dialog( title, obj.StatusMessage, options );
$('#dialog').dialog('open');
}
Function for confirming shipping rates and selecting service addons prior to processing shipment request with USPS
usps_confirm_rates = function( obj ) {
var title = obj.Title;
var html = obj.StatusMessage;
var options = {
resizable: true,
width:800,
height:800,
modal:true,
buttons: {
//This function is fired when the button on the first modal above is clicked.
'Process Shipment': function() {
data = {
action: 'usps_ajax',
call: 'process_shipment',
post: $('#post_id').val(),
};
ajax_request( data );
},
'Cancel': function(e) {
$(this).dialog( 'close' );
}
}
}
show_dialog( title, html, options );
var total_shipping = parseFloat( $('#total_shipping').text() );
var customer_paid = parseFloat( $('#shipping_paid').text() );
var total_addons = parseFloat( $('#total_addons').text() );
var difference;
$('.btn_addons').click( function(e) {
var key = $(this).attr('id');
$('#' + key + '_addon_options').slideToggle();
$('.cb_addon_sel').change( function(e) {
var addons = obj.AddOns;
var thisCheck = $(this);
var thisTable = $(this).closest('table').attr('id');
var curr_addon = $(this).val();
var addon_name = $("#" + curr_addon + "_name").text();
var thisAddon = new Array();
var price = get_price( thisTable, curr_addon );
if( obj.AddOns[thisTable][curr_addon].ProhibitedWithAnyOf !== undefined ) {
var prohibited = obj.AddOns[thisTable][curr_addon].ProhibitedWithAnyOf.AddOnTypeV5;
}
if( obj.AddOns[thisTable][curr_addon].RequiresAllOf !== undefined ) {
var required = obj.AddOns[thisTable][curr_addon].RequiresAllOf.RequiresOneOf.AddOnTypeV5;
}
if($(this).attr('checked') ) {
total_addons += parseFloat( price );
total_shipping += parseFloat( price );
if( addons_selected[thisTable] === undefined )
addons_selected[thisTable] = new Array();
addons_selected[thisTable].push( curr_addon );
for( var p in prohibited ) {
if( typeof prohibited === 'object' )
element = prohibited[p];
else
element = prohibited;
$('#' + thisTable + '_row_' + element).hide();
if( $('#' + thisTable + '_' + element).attr('checked') ) {
$('#' + thisTable + '_' + element).removeAttr('checked');
}
}
for( var r in required ) {
if( typeof required === 'object' )
element = required[r];
else
element = required;
price = get_price( thisTable, element);
$('#' + thisTable + '_' + element).attr('checked', 'checked');
total_addons += parseFloat( price );
total_shipping += parseFloat( price );
}
} else {
var name = addon_required( curr_addon, thisTable );
if( typeof name === 'string' ) {
$('#' + curr_addon + '_info').text('Required when ' + name + ' is selected.');
$('#' + thisTable + '_' + curr_addon).attr('checked','checked');
} else {
total_addons -= parseFloat( price );
total_shipping -= parseFloat( price );
for( var p in prohibited ) {
if( typeof prohibited === 'object' )
element = prohibited[p];
else
element = prohibited;
$('#' + thisTable + '_row_' + element).show();
//removeByValue( prohibited[p], prohibited );
}
for( var r in required ) {
if( typeof required === 'object' )
element = required[r];
else
element = required;
price = get_price( thisTable, element);
$('#' + thisTable + '_' + element).attr('checked', 'checked');
$('#' + thisTable + '_' + element).removeAttr('checked');
$('#' + element + '_info').text('');
total_addons -= parseFloat( price );
total_shipping -= parseFloat( price );
//removeByValue( required[r], required );
}
removeByValue( curr_addon, addons_selected[thisTable] );
}
}
difference = customer_paid - total_shipping;
$('#total_addons').text( total_addons.toFixed(2) );
$('#total_shipping').text( total_shipping.toFixed(2) );
$('#total_difference').text( difference.toFixed(2) );
});
});
function addon_required( addon, box ) {
if( typeof required === 'undefined' ) {
return false;
} else {
for(var a in addons_selected[box]) {
var reqs = obj.AddOns[box][addons_selected[box][a]].RequiresAllOf.RequiresOneOf.AddOnTypeV5;
if( $.inArray(addon, reqs) == -1) {
return false;
} else {
return $("#" + addons_selected[a] + "_name").text();
}
}
}
}
function get_price( box, addon ) {
if( obj.AddOns[box][addon].Amount === undefined ) {
price = 0.00;
} else {
price = obj.AddOns[box][addon].Amount;
}
return price;
}
}
So I was unable to fix the issue directly, so I created a workaround per se. Instead of using the dialog buttons as navigation, I added control buttons to the dialog content in php. I then access them directly via Jquery. See example below.
public function verify_address( $authenticator ) {
$order = $this->order;
$params = array(
'Authenticator' => $authenticator,
'Address' => array(
'FullName' => $order->shipping_first_name . ' ' . $order->shipping_last_name,
'Company' => $order->shipping_company,
'Address1' => $order->shipping_address_1,
'Address2' => $order->shipping_address_2,
'City' => $order->shipping_city,
'State' => $order->shipping_state,
'Zipccode' => $order->shipping_postcode,
'Country' => $order->shipping_country
),
);
$check = $this->stamps->CleanseAddress( $params );
$this->xml_response['Call'] = 'VerifyAddress';
if( ! $check->AddressMatch ) {
if( $check->CityStateZipOK ) {
$this->xml_response['ResponseStatusCode'] = 1;
$this->xml_response['VStatus'] = 'CityStateZipOK';
$this->xml_response['StatusMessage'] = 'The street address could not be verified; however, the City, State, & ZipCode are valid. Click continue to use this address or cancel.';
}
$this->xml_response['ResponseStatusCode'] = 0;
$this->xml_response['VStatus'] = 'InvalidAddress';
$this->xml_response['StatusMessage'] = 'invalid address. Please verify address and resubmit.';
} else {
$message = '<span id="usps_error"></span></br>';
$message .= "The address was matched. Please review updated address below and click continue to proceed.";
$message .= '<table><tr><td><input type="checkbox" id="verified" value="true" /></td>';
$message .= '<td>' . $check->Address->FullName . '</br>';
$message .= $check->Address->Address1 . '</br>';
$message .= count( $check->Address->Address2 ) < 0 ? $check->Address->Address2 . '</br>' : '';
$message .= $check->Address->City . ', ' . $check->Address->State . ' ' . $check->Address->ZIPCode . '-' . $check->Address->ZIPCodeAddOn . '</td></tr><table>';
//Added html button here for navigation purposes. This can be accessed by its ID in Js after it is added to the dialog box.
$message .= '</br></br><div><button class="dialog_nav" id="btn_continue">Continue</button></div>';
$this->xml_response['ResponseStatusCode'] = 1;
$this->xml_response['VStatus'] = 'AddressMatch';
$this->xml_response['StatusMessage'] = $message;
$this->xml_response['Authenticator'] = $check->Authenticator;
$this->xml_response['Method'] = 'USPS';
$this->xml_response['Title'] = 'Step 1: Address Verfication';
}
if( is_soap_fault( $check ) ) {
$this->xml_response = handle_errors( $check );
}
return $this->xml_response;
}
Then in JS I can access the button via jQuery.
usps_address_check = function( obj ) {
if( obj.VStatus === 'AddressMatch' ) {
var title = obj.Title;
var options = {
resizable: false,
width:800,
modal:true,
buttons: {
//Cancel button functions correctly
'Cancel': function() {
$(this).dialog( 'close' );
}
}
}
show_dialog( title, obj.StatusMessage, options );
$('#dialog').dialog('open');
//Button is accessed here and is code is only executed once.
$('#btn_continue').click( function(e) {
if( $('#verified').attr('checked') ) {
data = {
action: 'usps_ajax',
call: 'check_rate',
post: $('#post_id').val(),
};
ajax_request( data );
} else {
$('#usps_error').text("Please click the checkbox to confirm corrected address, and click continue to proceed." ).css('color','red');
}
});
}
}
Still looking for a better solution, but this will work for now.
Related
I have a problem with a checkbox: when doing a LIVEsearch, the value of the checkbox is always set to 1/true. When i do the same thing in a normal search (without the js file) i dont have this problem.
First of all the code of my checkbox:
{{ Form::checkbox('deleted', '1' , null , array('id' => 'search-deleted'))}}
Than the Code of my javascript (i guess the problem is to get the value of the checkbox)
<script>
$(document).ready(function(){
$(".search").keyup(function(){
var staffid= $("#search-staffid").val();
var firstName= $("#search-first-name").val();
var lastName= $("#search-last-name").val();
var birthday= $("#search-birthday").val();
var children= $("#search-children").val();
var deleted= $("#search-deleted").val();
if(staffid == "" && firstName == "" && lastName == "" && birthday == "" && children == "" ) {
$( "#liveResult" ).html("<b>Suchergebnisse werden hier angezeigt</b>");
}else {
$.get( "{{ url('demos/livesearch') }}" +
'?staffid=' + staffid +
'&first_name=' + firstName +
'&last_name=' + lastName +
'&birthday=' + birthday +
'&children=' + children +
'&deleted=' + deleted
, function( data ) {
$( "#liveResult" ).html( data );
});
}
});
});
</script>
As you see i have some other fields, they work without any problems. Finally the Code of my controller:
public function liveSearch(Request $request)
{
$data = [
'id' => $request->staffid,
'first_name' => $request->first_name,
'last_name' => $request->last_name,
// converts date format only if birthday != null
'birthday' => ($request->birthday ? date('Y-m-d', strtotime($request->birthday)) : null),
'children' => $request->children,
'deleted' => $request->deleted
];
if (is_null($data['id']) && is_null($data['first_name']) && is_null($data['last_name']) && is_null($data['birthday']) && is_null($data['children']))
{
return view('staff.livesearch');
}
else
{
dd ($data['deleted']);
}
}
The value of your checkbox is always 1; what you really want to know is whether or not it is checked.
// boolean
var deleted = $("#search-deleted").prop('checked');
$( document ).ready( function() {
var dynamicChargableForm = 1;
var dynamicDiscountForm = 1;
var selectedId = 1;
var newTextarea = null;
var chargableHeader = document.getElementById( 'chargable-header' );
var disountHeader = document.getElementById( 'discount-header' );
var execute = null;
$(document).on('keyup','.dynamic',function() {
var typeName = this.id.split('-')[0];
switch( typeName ) {
case 'chargable':
execute = dynamicRow( this, 'chargable', dynamicChargableForm , chargableHeader );
execute ? dynamicChargableForm++ : execute = null;
break;
case 'discount' :
execute = dynamicRow( this, 'discount', dynamicDiscountForm, disountHeader );
execute ? dynamicDiscountForm++ : execute = null;
break;
}
});
});
function dynamicRow( element, type , relatedTracker , relatedHeader )
{
selectedId = element.id.split('-')[1];
if ( selectedId == relatedTracker )
{
relatedTracker++;
newTextarea = document.createElement( 'TEXTAREA' );
newTextarea.setAttribute( 'name', type + '-' + relatedTracker );
newTextarea.setAttribute( 'class' , 'form-control dynamic ' + type );
newTextarea.setAttribute( 'id' , type + '-' + relatedTracker );
relatedHeader.append( newTextarea );
return true;
}
return false;
}
This is my first attempt to add a dynamically populate textarea when user input on the last added form . I would like to have advise and review on my code as i think that this code is not very efficient. I would like to have better understanding and standpoint from the expert.
Thank you
Replace
execute = dynamicRow( this, 'chargable', dynamicChargableForm , chargableHeader );
execute ? dynamicChargableForm++ : execute = null;
By
if(dynamicRow( this, 'chargable', dynamicChargableForm , chargableHeader )) {
dynamicChargableForm++;
}
I don't know why you need to add the dynamic name. Best way would be to set the name to chargable[]. The field will then be sent to the server as array.
I have the following code to perform an auto-completion for an input when introducing characters.
The problem I'm having is that with this function if I type in "En" it returns not only all the words starting with "En" (example: English, England, Enterprise, etc) but any word that contains the string of characters "En" anywhere (example: cENtral, cENtury, calENdar, etc)
What change do I need to make in my code to get only those words that start with the characters I type in?
It seams that the query is not getting update each time I introduce a character.
My Code:
<?php
include("config.php");
$db = pg_connect("$db_host $db_name $db_username $db_password");
$termfilter = $GET['term'];
$query = "SELECT * FROM cities WHERE city LIKE '$termfilter%'";
$result = pg_query($query);
if (!$result) {
echo "Problem with query " . $query . "<br/>";
echo pg_last_error();
exit();
}
$get_total_rows = pg_numrows($result);
$i = $get_total_rows;
while($myrow = pg_fetch_assoc($result)) {
$city = $myrow[city];
$country = $myrow[country];
if ($i == $get_total_rows){
$list = "'" . $city . " (" . $country . ")'";
$i = $i -1;
}
else {$list = $list . ", '" . $city . " (" . $country . ")'";}
}
?>
<center>
<form name="form1" method="post" action="searchresults.php" >
<input id="hero-demo" autofocus type="search" name="search" placeholder="City" >
<input type="submit" name="submit" value="Search">
</form>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="js/jquery.auto-complete.js"></script>
<script>
$(function(){
$('#hero-demo').autoComplete({
minChars: 2,
source: function(term, suggest){
term = term.toLowerCase();
var choices = [<?= $list ?>];
var suggestions = [];
for (i=0;i<choices.length;i++)
if (~choices[i].toLowerCase().indexOf(term)) suggestions.push(choices[i]);
suggest(suggestions);
}
});
});
</script>
My question is how do I get
$termfilter = $GET['term']; from so each time a new letter is type in, the query is execute and the value typed in is passed to $termfilter = $GET['term'];?
Additional code from the js/jquery.auto-complete.js file in case is need it
(function($){
$.fn.autoComplete = function(options){
var o = $.extend({}, $.fn.autoComplete.defaults, options);
// public methods
if (typeof options == 'string') {
this.each(function(){
var that = $(this);
if (options == 'destroy') {
$(window).off('resize.autocomplete', that.updateSC);
that.off('blur.autocomplete focus.autocomplete keydown.autocomplete keyup.autocomplete');
if (that.data('autocomplete'))
that.attr('autocomplete', that.data('autocomplete'));
else
that.removeAttr('autocomplete');
$(that.data('sc')).remove();
that.removeData('sc').removeData('autocomplete');
}
});
return this;
}
return this.each(function(){
var that = $(this);
// sc = 'suggestions container'
that.sc = $('<div class="autocomplete-suggestions '+o.menuClass+'"></div>');
that.data('sc', that.sc).data('autocomplete', that.attr('autocomplete'));
that.attr('autocomplete', 'off');
that.cache = {};
that.last_val = '';
that.updateSC = function(resize, next){
that.sc.css({
top: that.offset().top + that.outerHeight(),
left: that.offset().left,
width: that.outerWidth()
});
if (!resize) {
that.sc.show();
if (!that.sc.maxHeight) that.sc.maxHeight = parseInt(that.sc.css('max-height'));
if (!that.sc.suggestionHeight) that.sc.suggestionHeight = $('.autocomplete-suggestion', that.sc).first().outerHeight();
if (that.sc.suggestionHeight)
if (!next) that.sc.scrollTop(0);
else {
var scrTop = that.sc.scrollTop(), selTop = next.offset().top - that.sc.offset().top;
if (selTop + that.sc.suggestionHeight - that.sc.maxHeight > 0)
that.sc.scrollTop(selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight);
else if (selTop < 0)
that.sc.scrollTop(selTop + scrTop);
}
}
}
$(window).on('resize.autocomplete', that.updateSC);
that.sc.appendTo('body');
that.sc.on('mouseleave', '.autocomplete-suggestion', function (){
$('.autocomplete-suggestion.selected').removeClass('selected');
});
that.sc.on('mouseenter', '.autocomplete-suggestion', function (){
$('.autocomplete-suggestion.selected').removeClass('selected');
$(this).addClass('selected');
});
that.sc.on('mousedown click', '.autocomplete-suggestion', function (e){
var item = $(this), v = item.data('val');
if (v || item.hasClass('autocomplete-suggestion')) { // else outside click
that.val(v);
o.onSelect(e, v, item);
that.sc.hide();
}
return false;
});
that.on('blur.autocomplete', function(){
try { over_sb = $('.autocomplete-suggestions:hover').length; } catch(e){ over_sb = 0; } // IE7 fix :hover
if (!over_sb) {
that.last_val = that.val();
that.sc.hide();
setTimeout(function(){ that.sc.hide(); }, 350); // hide suggestions on fast input
} else if (!that.is(':focus')) setTimeout(function(){ that.focus(); }, 20);
});
if (!o.minChars) that.on('focus.autocomplete', function(){ that.last_val = '\n'; that.trigger('keyup.autocomplete'); });
function suggest(data){
var val = that.val();
that.cache[val] = data;
if (data.length && val.length >= o.minChars) {
var s = '';
for (var i=0;i<data.length;i++) s += o.renderItem(data[i], val);
that.sc.html(s);
that.updateSC(0);
}
else
that.sc.hide();
}
that.on('keydown.autocomplete', function(e){
// down (40), up (38)
if ((e.which == 40 || e.which == 38) && that.sc.html()) {
var next, sel = $('.autocomplete-suggestion.selected', that.sc);
if (!sel.length) {
next = (e.which == 40) ? $('.autocomplete-suggestion', that.sc).first() : $('.autocomplete-suggestion', that.sc).last();
that.val(next.addClass('selected').data('val'));
} else {
next = (e.which == 40) ? sel.next('.autocomplete-suggestion') : sel.prev('.autocomplete-suggestion');
if (next.length) { sel.removeClass('selected'); that.val(next.addClass('selected').data('val')); }
else { sel.removeClass('selected'); that.val(that.last_val); next = 0; }
}
that.updateSC(0, next);
return false;
}
// esc
else if (e.which == 27) that.val(that.last_val).sc.hide();
// enter or tab
else if (e.which == 13 || e.which == 9) {
var sel = $('.autocomplete-suggestion.selected', that.sc);
if (sel.length && that.sc.is(':visible')) { o.onSelect(e, sel.data('val'), sel); setTimeout(function(){ that.sc.hide(); }, 20); }
}
});
that.on('keyup.autocomplete', function(e){
if (!~$.inArray(e.which, [13, 27, 35, 36, 37, 38, 39, 40])) {
var val = that.val();
if (val.length >= o.minChars) {
if (val != that.last_val) {
that.last_val = val;
clearTimeout(that.timer);
if (o.cache) {
if (val in that.cache) { suggest(that.cache[val]); return; }
// no requests if previous suggestions were empty
for (var i=1; i<val.length-o.minChars; i++) {
var part = val.slice(0, val.length-i);
if (part in that.cache && !that.cache[part].length) { suggest([]); return; }
}
}
that.timer = setTimeout(function(){ o.source(val, suggest) }, o.delay);
}
} else {
that.last_val = val;
that.sc.hide();
}
}
});
});
}
$.fn.autoComplete.defaults = {
source: 0,
minChars: 3,
delay: 150,
cache: 1,
menuClass: '',
renderItem: function (item, search){
// escape special characters
search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi");
return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item.replace(re, "<b>$1</b>") + '</div>';
},
onSelect: function(e, term, item){}
};
}(jQuery));
Thanks
What change do I need to make in my code to get only those words that start with the characters I type in?
This line of code pushes a choice into the suggestion list if term matches anywhere in choices[i]:
if (~choices[i].toLowerCase().indexOf(term)) suggestions.push(choices[i]);
What you want is to push it to the list only if choices[i] matches the beginning of term:
if (choices[i].toLowerCase().indexOf(term) === 0) suggestions.push(choices[i]);
(Meanwhile, you have other stuff going on serverside that I'm honestly not quite following. If you're requesting the full list of data once, and then doing the per-keystroke autocomplete suggestions against that full list in javascript, then you should be all good. But if you're trying to make new server requests on every keystroke, and/or are attempting to do the filtering both server- and client-side, then... don't do that; it's going to be laggy and unresponsive.)
Many changes needed in your code,one change here, use quotes
$city = $myrow["city"];
$country = $myrow["country"];
Are you sure about the query or it should be
$query = "SELECT * FROM cities WHERE city LIKE '%$termfilter%'";
Also use full php code <?php ?> not <?= ?>
I am trying to Place the ColumnFilterWidget plugin in the Header of the Datatables Table.
Here are the changes i made in it :
/**
* Menu-based filter widgets based on distinct column values for a table.
*
* #class ColumnFilterWidgets
* #constructor
* #param {object} oDataTableSettings Settings for the target table.
*/
var ColumnFilterWidgets = function( oDataTableSettings ) {
var me = this;
var sExcludeList = '';
// me.$WidgetContainer = $( '<div class="column-filter-widgets"></div>' );
me.$WidgetContainer = $( '<tr class="head"></tr>' );
me.$MenuContainer = me.$WidgetContainer;
me.$TermContainer = null;
me.aoWidgets = [];
me.sSeparator = '';
if ( 'oColumnFilterWidgets' in oDataTableSettings.oInit ) {
if ( 'aiExclude' in oDataTableSettings.oInit.oColumnFilterWidgets ) {
sExcludeList = '|' + oDataTableSettings.oInit.oColumnFilterWidgets.aiExclude.join( '|' ) + '|';
}
if ( 'bGroupTerms' in oDataTableSettings.oInit.oColumnFilterWidgets && oDataTableSettings.oInit.oColumnFilterWidgets.bGroupTerms ) {
me.$MenuContainer = $( '<div class="column-filter-widget-menus"></div>' );
me.$TermContainer = $( '<div class="column-filter-widget-selected-terms"></div>' ).hide();
}
}
// Add a widget for each visible and filtered column
$.each( oDataTableSettings.aoColumns, function ( i, oColumn ) {
var $columnTh = $( oColumn.nTh );
var $WidgetElem = $( '<th><div class="column-filter-widget"></div></th>' );
if ( oColumn.bVisible && sExcludeList.indexOf( '|' + i + '|' ) < 0 ) {
me.aoWidgets.push( new ColumnFilterWidget( $WidgetElem, oDataTableSettings, i, me ) );
}
me.$MenuContainer.append( $WidgetElem );
} );
if ( me.$TermContainer ) {
me.$WidgetContainer.append( me.$MenuContainer );
me.$WidgetContainer.append( me.$TermContainer );
}
oDataTableSettings.aoDrawCallback.push( {
name: 'ColumnFilterWidgets',
fn: function() {
$.each( me.aoWidgets, function( i, oWidget ) {
oWidget.fnDraw();
} );
}
} );
return me;
};
I added a extra <tr class='head'> inside the Datatable, and later on i am trying to append the Filters to that with attached to them,But instead of that it is creating new TR tag and then appending the filters in it.
I even changed my dom of data tables to : dom: '<"clear">Cf<"clear">ltWrip',
So the table elements should be there so that it can insert filters inside the head.
FOUND THE ANSWER
Here is it if anyone else needs it .
Add a <TR id='Filter.$i'> element in the html
Use a for loop and append the counter value to the ID.
then modified the column.filterwidget plugn js
var ColumnFilterWidgets = function( oDataTableSettings ) {
var me = this;
var sExcludeList = '';
me.$WidgetContainer = $( '<div class="column-filter-widgets"></div>' );
me.$MenuContainer = me.$WidgetContainer;
me.$TermContainer = null;
me.aoWidgets = [];
me.sSeparator = '';
if ( 'oColumnFilterWidgets' in oDataTableSettings.oInit ) {
if ( 'aiExclude' in oDataTableSettings.oInit.oColumnFilterWidgets ) {
sExcludeList = '|' + oDataTableSettings.oInit.oColumnFilterWidgets.aiExclude.join( '|' ) + '|';
}
if ( 'bGroupTerms' in oDataTableSettings.oInit.oColumnFilterWidgets && oDataTableSettings.oInit.oColumnFilterWidgets.bGroupTerms ) {
me.$MenuContainer = $( '<div class="column-filter-widget-menus"></div>' );
me.$MenuContainer = $( '<div class="column-filter-widget-menus"></div>' );
me.$TermContainer = $( '<div class="column-filter-widget-selected-terms"></div>' ).hide();
}
}
var cnt= 0;
// Add a widget for each visible and filtered column
$.each( oDataTableSettings.aoColumns, function ( i, oColumn ) {
var $columnTh = $( oColumn.nTh );
cnt ++;
var $WidgetElem = $( '<div class="column-filter-widget" id=col'+cnt+'></div>' );
if ( oColumn.bVisible && sExcludeList.indexOf( '|' + i + '|' ) < 0 ) {
me.aoWidgets.push( new ColumnFilterWidget( $WidgetElem, oDataTableSettings, i, me ) );
}
var Tcol = document.getElementById('A');
console.log('---------'+i);
//me.$MenuContainer.append( $WidgetElem );
$('#Filter'+i).append( $WidgetElem );
} );
if ( me.$TermContainer ) {
me.$WidgetContainer.append( me.$MenuContainer );
me.$WidgetContainer.append( me.$TermContainer );
}
oDataTableSettings.aoDrawCallback.push( {
name: 'ColumnFilterWidgets',
fn: function() {
$.each( me.aoWidgets, function( i, oWidget ) {
oWidget.fnDraw();
} );
}
} );
return me;
};
Hope this helps.
I need help, I am trying to be able to apply different colors to the cells of an Extjs4 DatePicker component, I would like to say for example, if a specific day has uncomplete tasks mark that day as red.
Thanks in advance.
I already found a way to apply different colors to specific cells of an Extjs 4 DatePicker, I created a new component that extends form DatePicker and adds the cell coloring functionality.
I will copy the code here as I dont konw how to attach a file here :P
Ext.define('Framework.ux.form.EnhancedDatePicker', {
extend: 'Ext.picker.Date',
alias: 'widget.enhanceddatepicker',
yearMonthDictionary: {},
selectedCell: undefined,
fullUpdate: function(argDate){
this.callParent(arguments);
this.storeOriginalYearMonthClassNames();
this.addCurrentYearMonthClasses();
this.addSelectedCellClass();
},
storeOriginalYearMonthClassNames: function(){
var tmpCells = this.cells.elements;
for(var tmpIndex=0; tmpIndex < this.numDays;tmpIndex++) {
var tmpCell = tmpCells[tmpIndex];
var tmpCellDate = new Date(tmpCell.title);
var tmpClassName = tmpCell.className;
if( this.isCellSelected(tmpCell) ){
this.selectedCell = tmpCell;
tmpClassName = tmpCell.className.replace("x-datepicker-selected","");
}
this.storeYearMonthClassName(tmpCellDate,'originalClassName',tmpClassName);
}
},
isCellSelected: function(argCell){
if( Ext.isEmpty(argCell) ){
return false;
}
if( argCell.className.indexOf('x-datepicker-selected') >= 0 ){
return true;
}
return false;
},
storeYearMonthClassName: function(argDate,argField,argClassName){
if( Ext.isEmpty(argDate) || Ext.isEmpty(argField) ){
return;
}
var tmpMonthYearKey = argDate.getFullYear() + "-" + argDate.getMonth();
var tmpYearMonthValues = this.yearMonthDictionary[tmpMonthYearKey];
if( Ext.isEmpty(tmpYearMonthValues) ){
tmpYearMonthValues = {};
}
var tmpValue = tmpYearMonthValues[argDate.getDate()];
if( Ext.isEmpty(tmpValue) ){
tmpValue = {};
}
tmpValue[argField] = argClassName;
tmpYearMonthValues[argDate.getDate()] = tmpValue;
this.yearMonthDictionary[tmpMonthYearKey] = tmpYearMonthValues;
},
setDateClass: function(argDate,argClass){
if( Ext.isEmpty(argDate) ){
return;
}
var tmpCurrentDate = this.getValue();
var tmpCurrentMonthYearKey = tmpCurrentDate.getFullYear() + "-" + tmpCurrentDate.getMonth();
var tmpYearMonthKey = argDate.getFullYear() + "-" + argDate.getMonth();
this.addDateAndClassToDictionary(argDate,argClass);
this.addCurrentYearMonthClasses();
},
addDateAndClassToDictionary: function(argDate,argClass){
if( Ext.isEmpty(argDate) ){
return;
}
this.storeYearMonthClassName(argDate,'newClassName',argClass);
},
addCurrentYearMonthClasses: function(){
var tmpCells = this.cells.elements;
for(var tmpIndex=0; tmpIndex < this.numDays;tmpIndex++) {
var tmpCell = tmpCells[tmpIndex];
var tmpCellDate = new Date(tmpCell.title);
var tmpValue = this.getYearMonthValueByDate(tmpCellDate);
if( tmpValue.newClassName === null || tmpValue.newClassName === undefined ){
continue;
}
var tmpNewClassName = tmpValue.originalClassName + " " + tmpValue.newClassName;
if( tmpNewClassName !== tmpCell.className ){
tmpCell.className = tmpNewClassName;
}
}
},
getYearMonthValueByDate: function(argDate){
if( Ext.isEmpty(argDate) ){
return;
}
var tmpMonthYearKey = argDate.getFullYear() + "-" + argDate.getMonth();
var tmpYearMonthValues = this.yearMonthDictionary[tmpMonthYearKey];
if( Ext.isEmpty(tmpYearMonthValues) ){
return null;
}
return tmpYearMonthValues[argDate.getDate()];
},
addSelectedCellClass: function(){
if( this.selectedCell.className.indexOf('x-datepicker-selected') >= 0 ){
return;
}
this.selectedCell.className = this.selectedCell.className + " x-datepicker-selected";
}
});
This is an example on how to use the component:
var tmpDatePicker = this.down('datepicker[itemId=datePickerTest]');
var tmpDate = new Date(2013,4,2);
tmpDatePicker.setDateClass(tmpDate,"cell-red");
With those code lines we are telling the component to apply the class 'cell-red' to the cell corresponding to the date '2013-4-2'.
I hope this can be useful for people that was trying to accomplish this in Extjs 4.