How to disable Chart JS tooltip when there is no value? - tooltip

I am using Chart JS v.1.0.2. When I have one line and missing data, the tooltip shows x-label.
Does anyone know how to disable the tooltip when the point value is null?
Thanks very much!

If you don't mind a few console messages you can throw an error to exit out of the tooltip method for null values, like so
var myLineChart = new Chart(ctx).Line(data, {
tooltipTemplate: function (d) {
if (d.value === null)
throw '';
else
// else return the normal tooltip text
return d.label + ': ' + d.value;
}
});
The alternative would be to extend the chart or write a custom tooltips function
Fiddle - http://jsfiddle.net/y4zunrx6/

Using chart.js 2.3.0 and angular-chart.js 1.1.1, I solved the problem globally by resolving the ChartJsProvider provider in my angular.module('shared').config(...) function and specifying a custom label callback for the tooltips option:
ChartJsProvider.setOptions({
tooltips: {
enabled: true,
//mode: 'single',
callbacks: {
label: function (tooltipItem, data) {
const tooltip = data.datasets[tooltipItem.datasetIndex];
const value = tooltip.data[tooltipItem.index];
return value === 0 ? null : tooltip.label + ': ' + value;
}
}
}
});
By returning null the tooltip is not shown for that specific tooltipItem.
Reference: Chart.js Tooltip Configuration

I wanted to disable the tooltip all times. The version I'm using is 2.1.6, and I did it like this:
var options = {
tooltips : {
enabled: false
}
};
Note: This will not display tool-tip at all, use it only when you want to disable the tool-tip appearing.

Better approach is to customize tooltip template to show no data :
tooltipTemplate: "<%if (label && value){%><%=label%>: <%= value %><%} else {%> No data <%}%>"

Related

Hide selected items in select2

I'm trying to use select2 jQuery plugin to enhance a select element in HTML app. The select allow to choose multiple items.
I'll like to remove the items that are currently selected from the dropdown. I didn't find explicit solution in the docs.
The current solution I've found was to use templateResult option and have the template function return null if the item is selected. This cause Results.prototype.template function to set container.style.display = 'none' but this has the side-effect of causing the keyboard to still select those items even though they are not visible.
Just apply this CSS.
.select2-results__option[aria-selected=true] { display: none;}
Small Update for recent versions :
.select2-results__option--selected { display: none;}
Source
Check out the answer provided here, provided by Hakam Fostok.
I've reproduced his answer below here for completeness:
my solution was modified the select2.js (the core, version 4.0.3) in the line #3158. Add the following verification :
if ($option[0].selected == true) {
return;
}
With this verification, we can exclude from the dropdown list, the selected ones. And if you write the name of a selected option, appear the text of option "noResult" .
Here the complete code:
SelectAdapter.prototype.query = function (params, callback) {
var data = [];
var self = this;`
var $options = this.$element.children();`
$options.each(function () {
var $option = $(this);
if (!$option.is('option') && !$option.is('optgroup') ) {
return;
}
if ($option[0].selected == true) {
return;
}
var option = self.item($option);
var matches = self.matches(params, option);
if (matches !== null) {
data.push(matches);
}
});
callback({
results: data
});
};
For my purposes, I was using the select2.js file, so I made the change at line 3195.
For versions 4 and 4.1
.select2-container--default .select2-results__option[aria-selected=true] {
display: none !important;
}
Works fine!
In addition to #Satheez answer, this script will let you maintain the placeholder after hiding all the selected items.
$('.selector').select2().on("change", function (e) {
$('.select2-search__field').attr('placeholder', 'Here is your placeholder');
});

Set Umbraco Property Editor Input to jQueryUI Datepicker

I'm close but still can't quite get this to work.
I have a new custom property editor that is loading correctly and is doing almost everything expected until I try to set the text field to be a jQuery UI element.
As soon as I add a directive in Angular for setting it to call the jQuery UI datepicker function, I get the following error suggesting it hasn't loaded the jQueryUI script library correctly:
TypeError: Object [object Object] has no method 'datepicker'
Trouble is, I can't see where I should be adding it as the logical places (to my mind, at least) seem to make no difference. Here is the code in full:
function MultipleDatePickerController($scope, assetsService) {
//tell the assetsService to load the markdown.editor libs from the markdown editors
//plugin folder
//assetsService
// .load([
// "http://code.jquery.com/ui/1.10.4/jquery-ui.min.js"
// ])
// .then(function () {
// //this function will execute when all dependencies have loaded
// });
//load the seperat css for the editor to avoid it blocking our js loading
assetsService.loadCss("/css/jquery-ui.custom.min.css");
if (!$scope.model.value) {
$scope.model.value = [];
}
//add any fields that there isn't values for
//if ($scope.model.config.min > 0) {
if ($scope.model.value.length > 0) {
for (var i = 0; i < $scope.model.value.length; i++) {
if ((i + 1) > $scope.model.value.length) {
$scope.model.value.push({ value: "" });
}
}
}
$scope.add = function () {
//if ($scope.model.config.max <= 0 || $scope.model.value.length < $scope.model.config.max) {
if ($scope.model.value.length <= 52) {
$scope.model.value.push({ value: "" });
}
};
$scope.remove = function (index) {
var remainder = [];
for (var x = 0; x < $scope.model.value.length; x++) {
if (x !== index) {
remainder.push($scope.model.value[x]);
}
}
$scope.model.value = remainder;
};
}
var datePicker = angular.module("umbraco").controller("AcuIT.MultidateController", MultipleDatePickerController);
datePicker.directive('jqdatepicker', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
$(function () {
element.datepicker({
dateFormat: 'dd/mm/yy',
onSelect: function (date) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(date);
});
}
});
});
}
}
});
I faced the same problem when adapting a jQuery Date Range Picker for my Date Range Picker package for Umbraco 7. It's frustrating! The problem (I think) is that Angular's ng-model listens for "input" changes to trigger events and so doesn't pick up on a jQuery triggered event.
The way around it I found was to force the input event of the element you wish to update to fire manually, using jQuery's .trigger() event.
For example, the date picker I was using had this code for when a date was changed:
updateInputText: function () {
if (this.element.is('input')) {
this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
}
},
I just adapted it to force an input trigger by adding this.element.trigger('input') to the code block, so it now reads:
updateInputText: function () {
if (this.element.is('input')) {
this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
this.element.trigger('input');
}
},
This forces Angular to "see" the change and then ng-model is updated. There may well be a more elegant way (as I'm an Angular newbie), but I know this worked for me.
Got it. This is probably a bit of a hack, but it's simple and effective so it's a win nonetheless.
The assetsService call is the key, where I've put code into the deferred .then statement to call jQueryUI's datepicker on any item that has the "jqdp" CSS class:
//tell the assetsService to load the markdown.editor libs from the markdown editors
//plugin folder
assetsService
.load([
"/App_Plugins/Multidate/jquery-ui.min.js"
])
.then(function () {
//this function will execute when all dependencies have loaded
$('.jqdp').datepicker({ dateFormat: 'dd/mm/yy' });
});
I've then gone and added that class to my view:
<input type="text" jqdatepicker name="item_{{$index}}" ng-model="item.value" class="jqdp" id="dp-{{model.alias}}-{{$index}}" />
Finally, I've added a directive to ensure that dynamically-added items also display a datepicker:
datePicker.directive('jqdatepicker', function () {
return function (scope, element, attrs) {
scope.$watch("jqdatepicker", function () {
try{
$(element).datepicker({ dateFormat: 'dd/mm/yy' });
}
catch(e)
{}
});
};
});
As I said, this is possibly a bit hacky but it achieves the right result and seems like a simple solution.

Datepicker using Jquery loses focus to the textbox after date selected.

Datepicker using Jquery loses focus to the textbox after date selected. I am using jquery-ui-1.9.2.When a date is selected the focus not coming to the textbox.Any solution?
Try using the below code.
HTML code:
<input type="text" id="date"/>
JQuery:
$("#date").datepicker({
onClose: function () {
$(this).focus();
}
});
JSFiddle1
EDIT: The above code has a problem in IE, the datepicker is not getting closed. Here in this blog you can find the more information.
<script language='javascript' src="jquery-migrate-1.2.1.js"></script> // download and add this
$("#date").datepicker({
/* fix buggy IE focus functionality */
fixFocusIE: false,
onClose: function(dateText, inst) {
this.fixFocusIE = true;
this.focus();
},
beforeShow: function(input, inst) {
var result = $.browser.msie ? !this.fixFocusIE : true;
this.fixFocusIE = false;
return result;
}
});
JSFiddle2
$(".datepicker").datepicker({
onClose: function () {
$(this).parents().nextAll().find($(":input[type !='hidden']")).first().focus();
}
});
});
I have found an easier way that will put the focus on the next input, no matter how nested it is. You can always swap out the condition after the .find to whatever you like and it will bring the focus to that.
Initialise all the datepcikers on Doc Ready
$('.datepicker').datepicker(
{
onClose: function () {
this.focus();
}
});
Exapnding Praveen's answer.
I had one problem with it. On IE datepicker refused to show up each odd time I focused a field.
Also, there was a slight logical issue with that solution (which did not affect anything, but still not correct to my eye): fixFocusIE field is being set on options, but then later it is being called on "this", when "this" refers to DOM element and not options object. So essentially there are two fixFocusIE - one in options (unused) and the second one on DOM element itself.
And also $.browser.msie did not work anymore, I had to invent my own IE detector.
My working code looks like that:
var el = $("selector of element I need to assign to datepicker");
var options = {}; // actually I fill options from defaults and do some other manipulations, but I left it as empty object here for brevity
options.fixFocusIE = false;
function detectIE() {
var ua = window.navigator.userAgent;
if(ua.indexOf('MSIE ') > 0 ||
ua.indexOf('Trident/') > 0 ||
ua.indexOf('Edge/') > 0) {
return true;
}
// other browser
return false;
}
/* blur() and change() are needed to update Angular bindings, if any */
options.onSelect = function(dateText, inst) {
options.fixFocusIE = true;
$(this).blur().change().focus();
};
options.onClose = function(dateText, inst) {
options.fixFocusIE = true;
this.focus();
};
options.beforeShow = function(input, inst) {
var result = detectIE() ? !options.fixFocusIE : true;
options.fixFocusIE = false;
return result;
};
/* and this one will reset fixFocusIE to prevent datepicker from refusing to show when focusing the field for second time in IE */
el.blur(function(){
options.fixFocusIE = false;
});
el.datepicker(options);

Use jQuery to check and see if div element is empty

Below is the code I'm using to place a blur event on a text box in my ASP MVC 3 view. The code works fine if #MailingState is empty, however it cannot tell if #channelName is empty.
For example, if #channelName is empty but #MailingState is not, then when I place a value in #MailingZip the getDrmTerritory Ajax call is fired off every time.
Here is the jQuery
$('#MailingZip').blur(function () {
if ($('#AlignmentM').is(':checked')) {
if ($('#MailingState').val() != "" && $('#channelName').html() != "") {
getDrmTerritory($('#MailingZip').val(), $('#MailingState').val(), $('#channelName').html());
}
}
});
and here is the HTML for the #channelName segment it is checking
<div id="channelName" class="M-display-field">
#*this will be updated via ajax from Market Segment *#
#Html.DisplayFor(model => model.Channel, new { style = "margin-left: 300px;" } )
</div>
The section mentioned in the comments is updated via another jQuery method that looks like this
function ChangeChannel() {
//this function called if Market Segment changes, to update the channel
var pendistcode = document.getElementById('Pendist');
if (pendistcode == null) alert('Error: Cannot find Market Segment control');
//alert('!pendistcode value is ' + pendistcode.value);
$.ajax({
type: 'POST',
url: '/AgentTransmission/GetChannel/',
data: { pendist: pendistcode.value },
success: function (data) {
// alert("success: " + data);
$('#channelName').html(data);
$('#Channel').val(data);
},
error: function (data) {
alert("failure to obtain Channel name");
}
});
CheckTerritory('channel');
} //end ChangeChannel
That jQuery method (ChangeChannel) appends text to the channelName div which, when rendered with a value in it, looks like this
Here is the HTML you get when you inspect the Life Sales from that picture
You can check if #channelName is empty or not like this:
if ( $('#channelName').is(':empty') )
and combine with your code like this:
if ($('#MailingState').val() != "" && !$('#channelName').is(':empty'))
I put in an alert statment to find out channelName's length and it came back with 35, so there must obviously be some white space that gets rendered each time. I had to change the statement to the following to trim out the whitespace and add the variable to the condition.
var channel = $.trim($('#channelName').html());
if ($('#MailingState').val() != "" && channel != "")

Has any one used client_side_validations gem with Chosen.js dropdown?

I am using chosen.js (http://harvesthq.github.com/chosen/). I was wondering if anyone has been able to use chosen select boxes and client_side_validations together.
The issue is that when we use chosen it hides the original select element and renders its own dropdown instead, and when we focus out the validation isn't called and also when the validation message is shown it is shown with the original select element so positioning of the error isnt also correct.
What could be a good way to handle this, My be we can change some code inside ActionView::Base.field_error_proc which currently looks something like
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
unless html_tag =~ /^<label/
%{<div class="field_with_errors">#{html_tag}<label for="#{instance.send(:tag_id)}" class="message">#{instance.error_message.first}</label></div>}.html_safe
else
%{<div class="field_with_errors">#{html_tag}</div>}.html_safe
end
end
Any ideas ?
Edit 1:
I have the following solution that is working for me now.
applied a class "chzn-dropdown" to all my selects that were being displayed by chosen
used the following callback provided by client_side_validations Gem
clientSideValidations.callbacks.element.fail = function(element, message, callback) {
if (element.data('valid') !== false) {
if(element.hasClass('dropdown')){
chzn_element = $('#'+element.attr('id')+'_chzn');
console.log(chzn_element);
chzn_element.append("<label class='message-chzn'>"+message+"</label>");
}
else{
callback();
}
}
}
About the issue with the validation not running at all when the chosen selection changes you can try this:
selectbox.change(function() { setTimeout(function() { selectbox.focusout() }) });
I'm still looking for a solution about the validation message positioning because I'd really love to avoid tampering with the client side validations javascript.
EDIT:
It seems this is a good solution after all, to keep closer to the client side validations api I came up with the following (for whom it may concern):
var settings = {
type: 'ActionView::Helpers::FormBuilder',
input_tag: '<div class="field_with_errors"><span id="input_tag" /><label class="message validationError" /></div>'
};
clientSideValidations.callbacks.element.fail = function (element, message, addError) {
if ($(element).data('chosen') != null) {
var chosen = $('#' + element.attr('id') + '_chzn');
clientSideValidations.formBuilders[settings.type].add(chosen, settings, message);
// Point the label back to the select box
$('label[for="' + chosen.attr('id') + '"]').attr('for', element.attr('id'));
// Mark it as invalid
chosen.data('valid', false);
} else {
addError(element, message);
}
};
clientSideValidations.callbacks.element.pass = function (element, removeError) {
if (element.data('chosen') != null) {
var chosen = $('#' + element.attr('id') + '_chzn');
clientSideValidations.formBuilders[settings.type].remove(chosen, settings);
// Un-mark it from invalid
chosen.data('valid', null);
} else {
removeError(element);
}
};
Note that I use a data attribute (data-chosen) for initialising select-boxes with chosen. Also for a label click to open chosen to work, I explicitly open the list box on label click:
// element is the select box
// Delegate click event from related labels to element (this is already done on "good" browsers)
$('label[for="' + element.attr('id') + '"]').click(function() { element.click() });
// Delegate click event on original element and any related labels to open the list
$(element).click(function() { setTimeout(function() { element.trigger('liszt:open'); }, 0); });
clientSideValidations.callbacks.element.fail = function(element, message, callback){
if(element.data("valid") !== false) {
callback();
if(element.is("select") && $("#" + element.attr("id") + "_chzn").length > 0){
element.parent().prepend($("#" + element.attr("id") + "_chzn"));
}
}
}
Try this:
Tell the gem that you want to validate select tags:
ClientSideValidations.selectors.inputs += ', select';
Force validation when Chosen's dropbox changes:
$('#form_field').chosen().change(function(e) {
var settings = window.ClientSideValidations.forms[this.form.id];
$(this).isValid(settings.validators);
});
Since Chosen hides the field, you will need to enable validation for that field explicitly in the view:
<%= form_for ..., :validate => true do |f| %>
...
<%= f.validate :form_field %>
...
<% end %>

Resources