I've got a bunch of charts showing on a single page via the HighCharts cloud inject code. Because the data for each chart is quite large, the page gets massive if the user selects View data table from the menu - which I'm fine with, but I would prefer the user be able to Toggle the table triggered by the same menu button. Is there any way I could do this via the custom code?
I've figure dout how to change the text in the menu to Toggle data table, but can't figure out how to apply the toggle code.
This is what I have so far:
exporting: {
buttons: {
contextButton: {
enabled: true,
text: 'Download',
menuItems: ["printChart",
"separator",
"downloadPNG",
"downloadJPEG",
"downloadPDF",
"downloadSVG",
"separator",
"downloadCSV",
"downloadXLS",
{
textKey: 'viewData',
text: 'Toggle data table',
onclick: function() {
this.viewData()
}
}]
}
}
It seems that Highcharts doesn’t offer any method for hiding the data table. The workaround is to put the following logic in onclick event:
onclick: function() {
if (this.dataTableDiv && this.dataTableDiv.style.display !== 'none') {
this.dataTableDiv.style.display = 'none';
} else {
this.viewData();
this.dataTableDiv.style.display = '';
}
}
Live demo: http://jsfiddle.net/BlackLabel/2t1w4pu9/
Cloud doesn’t include export-data module in its editor but the generated inject-script does. So the functionality works outside the Cloud (e.g. on jsfiddle).
Related
I want to trigger the map info window from an outside link. For example, we add country link on the map sidebar and want to open the info window from the country list link.
http://projects.thesparxitsolutions.com/SIS415/business-world-map
You can open multiple description windows setting allowMultipleDescriptionWindows to true in your config and then calling clickMapObject on the desired areas to open them programmatically, for example:
AmCharts.makeChart("mapdiv", {
// ...
allowMultipleDescriptionWindows: true,
listeners: [
{
event: "rendered",
method: function(e) {
var map = e.chart;
//trigger the description windows for these regions
map.clickMapObject(map.getObjectById("FR-D"));
map.clickMapObject(map.getObjectById("FR-E"));
}
}
]
});
I'm using the amazing flatpickr on a project and need the calendar date to be mandatory.
I'm trying to have all the validation in native HTML, so I was naively trying with just adding the required attribute to the input tag, but that doesn't appear to be working.
Is there a way of natively making a date mandatory with flatpickr or do I need to write some custom checks?
You can easily achieve this by:
Passing allowInput:true in flatpickr config.
As example:
flatpickrConfig = {
allowInput: true, // prevent "readonly" prop
};
From the documentation:
Allows the user to enter a date directly into the input field. By
default, direct entry is disabled.
The downside of this solution is that you should enable the direct entry (but ideally form validation should occur whether or not direct entry is enabled).
But if you don't want to enable the direct entry to solve this problem, you can use the code below as a workaround:
flatpickrConfig = {
allowInput:true,
onOpen: function(selectedDates, dateStr, instance) {
$(instance.altInput).prop('readonly', true);
},
onClose: function(selectedDates, dateStr, instance) {
$(instance.altInput).prop('readonly', false);
$(instance.altInput).blur();
}
};
This code remove the readonly property when it is not in focus so that html validation can occur and add back the readonly prop when it is in focus to prevent manual input. More details about it here.
This is what I came up with to make as complete of a solution as possible. It prevents form submission (when no date selected and input is required), ensures browser native "field required" message pops up and prevents the user typing in the value directly.
flatpickrConfig = {
allowInput: true, // prevent "readonly" prop
onReady: function(selectedDates, dateStr, instance) {
let el = instance.element;
function preventInput(event) {
event.preventDefault();
return false;
};
el.onkeypress = el.onkeydown = el.onkeyup = preventInput; // disable key events
el.onpaste = preventInput; // disable pasting using mouse context menu
el.style.caretColor = 'transparent'; // hide blinking cursor
el.style.cursor = 'pointer'; // override cursor hover type text
el.style.color = '#585858'; // prevent text color change on focus
el.style.backgroundColor = '#f7f7f7'; // prevent bg color change on focus
},
};
There is one disadvantage to this: Keyboard shortcuts are disabled when the flatpickr is open (when the input has focus). This includes F5, Ctrl + r, Ctrl + v, etc. but excludes Ctrl + w in Chromium 88 on Linux for some reason. I developed this using a rather old flatpickr version 3.1.5, but I think it should work on more recent ones too.
In case you want to use altFormat (display one date format to user, send other date format to server), which also implies setting altInput: true, you have to also change the onReady function to use instance.altInput instead of instance.element.
The onReady event listener can probably be attached to the instance after initializing it. However, my intention of using flatpickr with vue-flatpickr-component where you cannot elegantly access the individual flatpickr instances, made me use the config field instead.
I haven't tested it on mobile devices.
After digging a bit into the GitHub repo, I found a closed issue that points out that the issue will not be addressed.
In the same Issue page there is a workaround that seems to do the trick:
$('.flatpickr-input:visible').on('focus', function () {
$(this).blur()
})
$('.flatpickr-input:visible').prop('readonly', false)
copy attr name from prior input type hidden to rendered flatpickr input
just do this
$('[name=date_open]').next('input').attr("name","date_open");
$('[name=date_close]').next('input').attr("name","date_close");
Have been working on this for a couple of days now, finally getting the result I was after.
NOTE: I am using flatpickr with jQuery validation
As you would know flatpickr uses an alternative field for the date input, the actual field where the date is stored is hidden, and this is the key.
jQuery validation has a set of defaults, and by default hidden fields are not subject to validation, which normally makes perfect sense. So we just have to turn on the validation of hidden fields to make this work.
$.validator.setDefaults({
ignore: []
});
So my validator rules are then fairly normal:
var valid = {
rules: { dateyearlevel: {required: true} },
messages: { dateyearlevel: {required: "The date is required"} }
};
$("#myform").validate(valid);
That should allow you to ensure the date is required.
In my situation I wanted my date to only be required is a checkbox was checked. To do this we changed the rule above:
var valid = {
rules: { dateyearlevel: {
required: function() { return $("#mycheckbox").is(":checked") }
} },
messages: { dateyearlevel: {required: "The date is required"} }
};
$("#myform").validate(valid);
In case this helps someone, I'm using parsley.js for frontend validation and it works good with flatpickr
enter image description here
Just to expand a bit more on this, I found the ignore value set as an empty array did the trick for me also. You can just add this to your validate call back. Also displaying was a bit of an issue so I updated the errorPlacement to allow for flatpickr inputs like so.
$('#my-form').validate({
errorPlacement: function (error, element) {
if (element.hasClass('js-flatpickr') && element.next('.js-flatpickr').length) {
error.insertAfter(element.next('.js-flatpickr'));
} else if (element.parent('.input-group').length) {
error.insertAfter(element.parent());
} else {
error.insertAfter(element);
}
},
ignore: [],
rules: {
'startdate': { required: true }
},
messages: {
'startdate': {required: "Start Date is required"}
},
submitHandler: function(form) {
// ajax form post
}
});
in my case vue ( dunno why ) , i would like to comment for comment by #mik13ST
fyi: the default allowInput i think is true, no need to define, i didnt set the properties and my flat-pickr also work on testing.
i use
// this work in flat-pickr || #code_01
<small class="text-danger">
{{ validationContext.errors[0] }}
</small>
instead of
// work for all element except <flat-pickr #code_02 , dunno why not work
<b-form-invalid-feedback>
{{ validationContext.errors[0] }}
</b-form-invalid-feedback>
full code
<validation-provider
#default="validationContext"
name="Waktu Selesai Berkegiatan *"
vid="Waktu Selesai Berkegiatan *"
rules="required"
>
<flat-pickr
id="Waktu Selesai Berkegiatan *"
v-model="item.pip_time_end_rl"
placeholder="Waktu Selesai Berkegiatan *"
class="form-control"
static="true"
:config="dpconfig"
:state="getValidationState(validationContext)"
/>
// put here the message of error ( required ) #code_01 instead of #code_02
</validation-provider>
if younot use composite,
just use
#default="{ errors }" // in validation provider
:state="errors.length > 0 ? false : null" // in element for example flat-pickr
{{ errors[0] }} // to print out the message
I'm new to Steroids and I'm trying to display a modal view with a button in the native navigation bar (will use it later for a side drawer).
Note: The use of a modal view doesn't require to override potential existing back button on the left side.
My view and its content are displayed normally with a nice NavigationBarButton "Filtres". But once the view is fully loaded the navigation bar is reloaded and the navigation bar button disappears.
Any idea why this happens and how fix it?
Here is the controller code:
angular
.module('profile-list')
.controller('IndexController', function($scope, supersonic) {
var drawerButton = new supersonic.ui.NavigationBarButton({
title: "Filtres",
onTap: function(){
supersonic.logger.debug("click");
}
});
var navigationBarOptions = {
buttons: {
left: [drawerButton]
}
};
supersonic.ui.navigationBar.update(navigationBarOptions);
});
Thanks
Try wrapping the navbar update like this:
supersonic.ui.views.current.whenVisible( function(){
var drawerButton = new supersonic.ui.NavigationBarButton({
title: "Filtres",
onTap: function(){
supersonic.logger.debug("click");
}
});
var navigationBarOptions = {
buttons: {
left: [drawerButton]
}
};
supersonic.ui.navigationBar.update(navigationBarOptions);
});
Also, you can test the button on the right side instead in case the overrideBackButton is somehow setting itself to true.
I have the following template:
<template name="modalTest">
{{session "modalTestNumber"}} <button id="modalTestIncrement">Increment</button>
</template>
That session helper simply is a go-between with the Session object. I have that modalTestNumber initialized to 0.
I want this template to be rendered, with all of it's reactivity, into a bootbox modal dialog. I have the following event handler declared for this template:
Template.modalTest.events({
'click #modalTestIncrement': function(e, t) {
console.log('click');
Session.set('modalTestNumber', Session.get('modalTestNumber') + 1);
}
});
Here are all of the things I have tried, and what they result in:
bootbox.dialog({
message: Template.modalTest()
});
This renders the template, which appears more or less like 0 Increment (in a button). However, when I change the Session variable from the console, it doesn't change, and the event handler isn't called when I click the button (the console.log doesn't even happen).
message: Meteor.render(Template.modalTest())
message: Meteor.render(function() { return Template.modalTest(); })
These both do exactly the same thing as the Template call by itself.
message: new Handlebars.SafeString(Template.modalTest())
This just renders the modal body as empty. The modal still pops up though.
message: Meteor.render(new Handlebars.SafeString(Template.modalTest()))
Exactly the same as the Template and pure Meteor.render calls; the template is there, but it has no reactivity or event response.
Is it maybe that I'm using this less packaging of bootstrap rather than a standard package?
How can I get this to render in appropriately reactive Meteor style?
Hacking into Bootbox?
I just tried hacked into the bootbox.js file itself to see if I could take over. I changed things so that at the bootbox.dialog({}) layer I would simply pass the name of the Template I wanted rendered:
// in bootbox.js::exports.dialog
console.log(options.message); // I'm passing the template name now, so this yields 'modalTest'
body.find(".bootbox-body").html(Meteor.render(Template[options.message]));
body.find(".bootbox-body").html(Meteor.render(function() { return Template[options.message](); }));
These two different versions (don't worry they're two different attempts, not at the same time) these both render the template non-reactively, just like they did before.
Will hacking into bootbox make any difference?
Thanks in advance!
I am giving an answer working with the current 0.9.3.1 version of Meteor.
If you want to render a template and keep reactivity, you have to :
Render template in a parent node
Have the parent already in the DOM
So this very short function is the answer to do that :
renderTmp = function (template, data) {
var node = document.createElement("div");
document.body.appendChild(node);
UI.renderWithData(template, data, node);
return node;
};
In your case, you would do :
bootbox.dialog({
message: renderTmp(Template.modalTest)
});
Answer for Meteor 1.0+:
Use Blaze.render or Blaze.renderWithData to render the template into the bootbox dialog after the bootbox dialog has been created.
function openMyDialog(fs){ // this can be tied to an event handler in another template
<! do some stuff here, like setting the data context !>
bootbox.dialog({
title: 'This will populate with content from the "myDialog" template',
message: "<div id='dialogNode'></div>",
buttons: {
do: {
label: "ok",
className: "btn btn-primary",
callback: function() {
<! take some actions !>
}
}
}
});
Blaze.render(Template.myDialog,$("#dialogNode")[0]);
};
This assumes you have a template defined:
<template name="myDialog">
Content for my dialog box
</template>
Template.myDialog is created for every template you're using.
$("#dialogNode")[0] selects the DOM node you setup in
message: "<div id='dialogNode'></div>"
Alternatively you can leave message blank and use $(".bootbox-body") to select the parent node.
As you can imagine, this also allows you to change the message section of a bootbox dialog dynamically.
Using the latest version of Meteor, here is a simple way to render a doc into a bootbox
let box = bootbox.dialog({title:'',message:''});
box.find('.bootbox-body').remove();
Blaze.renderWithData(template,MyCollection.findOne({_id}),box.find(".modal-body")[0]);
If you want the dialog to be reactive use
let box = bootbox.dialog({title:'',message:''});
box.find('.bootbox-body').remove();
Blaze.renderWithData(template,function() {return MyCollection.findOne({_id})},box.find(".modal-body")[0]);
In order to render Meteor templates programmatically while retaining their reactivity you'll want to use Meteor.render(). They address this issue in their docs under templates.
So for your handlers, etc. to work you'd use:
bootbox.dialog({
message: Meteor.render(function() { return Template.modalTest(); })
});
This was a major gotcha for me too!
I see that you were really close with the Meteor.render()'s. Let me know if it still doesn't work.
This works for Meteor 1.1.0.2
Assuming we have a template called changePassword that has two fields named oldPassword and newPassword, here's some code to pop up a dialog box using the template and then get the results.
bootbox.dialog({
title: 'Change Password',
message: '<span/>', // Message can't be empty, but we're going to replace the contents
buttons: {
success: {
label: 'Change',
className: 'btn-primary',
callback: function(event) {
var oldPassword = this.find('input[name=oldPassword]').val();
var newPassword = this.find('input[name=newPassword]').val();
console.log("Change password from " + oldPassword + " to " + newPassword);
return false; // Close the dialog
}
},
'Cancel': {
className: 'btn-default'
}
}
});
// .bootbox-body is the parent of the span, so we can replace the contents
// with our template
// Using UI.renderWithData means we can pass data in to the template too.
UI.insert(UI.renderWithData(Template.changePassword, {
name: "Harry"
}), $('.bootbox-body')[0]);
I am using fullcalendar 1.6.0, with qtip2, building an array in php and using this as the events list
$('#calendar').fullCalendar({
// put your options and callbacks here
events: [
<?php echo $eventlist; ?>
],
It is working fine, but I would now like to use the calendar in a 'mobile friendly' layout.
What I want to do is, at resolutions below a certain breakpoint, remove some or all of the event information from displaying within the calendar itself, (so a colored block appears on the calendar, but little or nothing else) but still appear in the qtip.
Can I use eventrender to do this ?
Yes. I think you can do this.
Below is the sample code. You have to use two events eventRender and eventAfterAllRender. or you can also hide the elements inside eventAfterAllRender.
eventRender: function (event, element, view) {
if( window.screen.width < 300 ) {
$('.fc-event-title').hide();
$('.fc-event-time').hide();
}
},
eventAfterAllRender: function( view ) {
$('.fc-event-inner').each(function(){
$(this).qtip(
{
content: $(this).children('.fc-event-time').html() + '' + $(this).children('.fc-event-title').html()
});
}
}
NOTE: This code is not tested. Change it according to your needs. Something like above will work for you.