Reload foundation all or partially - javascript

In my website, the main index.php have a drop-down menu, and if I click on an item, an Ajax loader work and writes in the main div of the main index.
But if this import use foundation function (reveal, callout, tabs..), this import doesn't work.
If in web explorer console I insert again this command '$(document).foundation();', import works but I receive in the log a warning
Tried to initialize drill down on an element that already has a Foundation plugin.
foundation.min.js:65 Tried to initialize dropdown-menu on an element that already has a Foundation plugin.foundation.min.js:65
Tried to initialize off-canvas on an element that already has a Foundation plugin.foundation.min.js:65
Tried to initialize responsive-toggle on an element that already has a Foundation plugin.foundation.min.js:65
Tried to initialize reveal on an element that already has a Foundation plugin.
Can somebody help me to find a clean solution to reload foundation?

In Foundation 6.2.3,
$(document).foundation()
will call
reflow: function(this, plugins)
with plugins undefined, so every plugin will be checked: The function will look at each child of $(document) with a [data-plugin_name] attribute and show this warning if that element already has been initialized:
if ($el.data('zfPlugin')) {
console.warn("Tried to initialize " + name + " on an element that already has a Foundation plugin.");
return;
}
So you can either call foundation() directly on the new element after your ajax request :
$('#your_element').foundation();
or call reflow with a specified plugin (eg. reveal)
Foundation.reflow($('document'), 'reveal')
provided you don't already have an initialized 'reveal' element in your DOM
Mixed: (best solution I think)
Foundation.reflow($('#your_element'), 'reveal');

Firstly, do not call $(document).foundation(); more than once.
If you've updated an element already initialized with a plugin, you'll need to use reInit.
If you've added or completely replaced an element with a new element you'll need to use $(element).foundation();
I use the following technique:
First, when foundation is initialized I store a global:
$(document).foundation();
__foundationRun = true;
Then, no matter when, the following util will handle initialization of new/updated elements:
function foundationUpdate(el) {
if (__foundationRun) {
if (el.data('zfPlugin'))
// existing element already has a plugin - update
Foundation.reInit(el);
else
// new element - initialize
el.foundation();
}
// else leave for foundation to init
}
So you could use like this:
$(".accordion").append("<li>Item</li>");
foundationUpdate($(".accordion"));
or
var newAccordion = $("<ul class='vertical menu accordion-menu'"
+ " data-accordion-menu><li>Item</li></ul>");
$(".container").append(newAccordion);
foundationUpdate(newAccordion);

Related

Trigger Bootstrap JS behavior for dynamically loaded HTML content

I am dynamically loading HTML templates containing Bootstrap markup. However, none of the Bootstrap Javascript behavior is being applied to the loaded content. For example, if the loaded content contained markup for the Bootstrap modal the modal doesn't behave correctly.
Is there a way I can trigger Bootstrap to refresh or apply it's Javascript to the newly loaded content?
you'll need to initialize the modal in the callback of whatever function/request object is loading the dynamic content
it's hard to say without seeing your code but something like this
require(['!text/myDynamicTemplate.html'], function(template){
//logic to render the template and/or insert it into the dom here
$('#myModal').modal(options)
})
Edit:
Bootstrap defines its javascript plugins individually. There is no global bootstrap object
Here's the plugin definition for tooltip
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tooltip')
var options = typeof option == 'object' && option
if (!data && /destroy|hide/.test(option)) return
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tooltip
$.fn.tooltip = Plugin
$.fn.tooltip.Constructor = Tooltip
// TOOLTIP NO CONFLICT
// ===================
$.fn.tooltip.noConflict = function () {
$.fn.tooltip = old
return this
}
}(jQuery);
Thus the only thing you get access to via $('#myID').tooltip is the constructor and initializer
the best you can do without modifying the bootstrap code
$('[data-toggle=tooltip]').tooltip()
Alert close buttons and model open buttons by default are already delegated. If there's a data-toggle attribute, it's delegated, except for tooltips and popovers. Tooltips and popovers are opt-in. Every other bootstrap js component may have a refresh method, for example the scrollspy script.
I usually add a function in which I apply the needed javascript like bootstrap (or WYSIWIG editors) to any scope.
There is also bootbox which might be helpful to you: http://bootboxjs.com/
As for bootstrap model loading via ajax, http://jschr.github.io/bootstrap-modal/ might be helpfull to you.
It's worth giving this a shot:
http://nakupanda.github.io/bootstrap3-dialog/#loading-remote-page
See more discussions:
https://github.com/nakupanda/bootstrap3-dialog/issues/217
https://github.com/nakupanda/bootstrap3-dialog/issues/189
https://github.com/nakupanda/bootstrap3-dialog/issues/185
https://github.com/nakupanda/bootstrap3-dialog/issues/119
https://github.com/nakupanda/bootstrap3-dialog/issues/44

Add class to dynamically generated HTML

I'm working to use custom checkbox styles with a checkbox which is dynamically generated by javascript for the Google Identity Toolkit. For example, we add this div:
<div id="gitkitWidgetDiv"></div>
And the Google Identity Toolkit script generates new html for that div.
I need to add a class to the HTML which is added by the javascript without any action by the user and I'm struggling to make it work. For example, here is my code:
$("#gitkitWidgetDiv").on('ready', ".gitkit-sign-in-options label", function() {
$(this).addClass('checkbox');
});
I've tried switching 'ready' for a few other options and also using the livequery plugin, but nothing is working for me. It works if I use an active event like 'click,' but I can't figure out how to do this when the page loads. Could someone please help? Thanks!
Modern browsers (including IE11) support mutation obervers. You can use one to monitor the parent node of the div that will be added. When the div has been added, just add the class.
Here's something I made which comes in handy in annoying cases like this where it's difficult to tell when the element you need has finished loading in: https://gist.github.com/DanWebb/8b688b31492632b38aea
so after including the function it'd be something like:
var interval = 500,
stopTime = 5000,
loaded = false;
setIntervalTimeout(function() {
if($('.dynanicElementClass').length && !loaded) {
$('.dynanicElementClass').addClass('checkbox');
loaded = true;
}
}, interval, stopTime);
It's not perfect and I'm sure there are better solutions out there but in most cases like this it does the job.

Can't launch lightbox from miithril View

I'm new to Mithril and trying to wrap my head around this issue.
I have a view that creates a DOM element and has a onClick method declared. Unfortunately when I tried to launch a lightbox such as magnificPopup, jqueryui dialog, fancybox or you name it, it calls the method undefined, even though the lightbox library is loaded.
Is this an issue with Mithril?
Here is my code:
m('a.view-link', {
onclick: function() {
$.colorbox(); // this fails
alert('here is the code'); // alerts do work
$('.view-link').css('border', '2px solid red'); // this works
// $('.white-popup').magnificPopup({ // this claims .magnificPopup is undefined
// type:'inline',
// midClick: true
// });
// $('#dialog').dialog('open'); //jqueryUI dialog claims that .dialog is undefined
},
href: '#'
} , ' Show link in lightbox')
The way Mithril works is by creating a virtual DOM (i.e. a plain-javascript data structure that represents a template), and then rendering this virtual DOM to create a real DOM tree.
When you call m(), you're building this virtual DOM, so at that point the DOM elements don't exist yet in the document. In order to integrate third party libraries, the correct way to do it is via the config attribute (see http://lhorie.github.io/mithril/mithril.html#accessing-the-real-dom-element )
In a nutshell, the config function gets called after rendering, and it takes the element as an argument, along with some other parameters to help control its lifecycle.
The syntax looks like this:
m("a.view-link", {config: function(el) {
$(el).colorbox() //initialize jquery plugin
}})
Might it be that $.colorbox(); is missing the 'subject' element?
$(this).colorbox(); should work better.

JQuery Mobile Custom Flipbox set initialization value

I have a custom flipbox which is described in the accepted answer here: JQuery Mobile Custom Flipbox get selected value.
I'm struggling to set the initial value after the page is rendered my 'change-page' function is something like this:
changePage:function (page) {
page.$el.attr('data-role', 'page');
page.render();
$('body').append(page.$el).trigger('create');
$.mobile.changePage(page.$el, {changeHash:false});
}
As I use Backbone.js to manage the views and then I delegate the navigation to jQM.
I basically need to set the initial value of this input text field ( maybe there's a workaround)
Ok I figured this out myself and I'm willing to share the solution:
first of all the change page function is slightly different:
changePage:function (page) {
page.$el.attr('data-role', 'page');
//get rid of everything in the old page.
page.remove();
//render the page again
page.render();
$('body').append(page.$el).trigger('create');
$.mobile.changePage(page.$el, {changeHash:false});
}
the remove call is necessary to get rid of every event listener you had in the old rendered HTML.
In every page that needs init parameters you can specify in the render function this:
render: function(){
....
this.$el.on('pageshow',this.initFields);
....
}
initFields: function(){
// put your jQuery code here (e.g. this.$el.find('foo').val('initValue');
}
please note that this solution as of the jQM documentation is valid up to the 1.5.0 version of jQM, after that the pageshow event will not be triggered anymore.

How do we set an onExpand event in a cfLayout accordion

We're using CFLayout to create a tab structure in our web application. After creation of that layout we call this function:
mytabs = ColdFusion.Layout.getTabLayout("#attributes.cflayoutName#");
mytabs.on('tabchange',
function(tablayout,tab) {
var tabtitle = tab.title;
alert(tabtitle); // Actual code does various useful 'stuff' here.
}
);
That piece of code works very well, and the alert will show each time the user clicks on a tab.
The problem is that we are now trying to do the same thing with a CFLayout type of "accordion", and I cannot get an event to fire when the user switches which accordion pane they are looking at. We've tried leaving the above as is, as well as changing the "tabchange" attribute to "expand", "beforeexpand", "activate", and "collapse".
For this testing I'm using the following simple JS function to avoid issues arising from the JS within the onchange event:
mytabs = ColdFusion.Layout.getAccordionLayout("#attributes.cflayoutName#");
mytabs.on('expand',
function(tablayout,tab) {
console.log('test');
}
);
We do not receive any errors. Nothing is logged to the console at all. I've tried replacing the console.log to an alert to rule out any problems with that line.
I found that the Ext library documentation to be very helpful with finding a solution to this problem: here.
The Ext library has a getComponent method that allows you to reference the accordion layout panel that you are trying to add the expand event to. Once you have this, you can use the "on" method you are using above to assign the expand event to each panel individually.
for (x=1; x<accordionLayoutArray.length; x++) {
mytabs.getComponent(accordionPanelName).on('expand',
function(tab) { ... });
}
This became too long for a comment so adding as an answer
After some Google searches I found what I think are some related posts. It appears as though the accordion in Ext JS does not have the same events as the tab. Instead you need to add a listener in order to catch the expanding.
See this post - in case something happens to that page here is the relevant piece:
You'd need to listen to the expand event of the child panels in the accordion, you could do something like:
Code:
myAccordion.add(myFunc('myTitle'));
function myFunc(title)
{
return new Ext.Panel(
{
title: title,
listeners: { 'expand': {fn: something, scope: foo}}
}
);
}
And I also found another similar post here on SO - see both answers
Once you know that the accordion needs a listener you can find a number of results on Google. Such as How do I attach an event handler to a panel in extJS?
This Google search will give you lots of examples.
Hope that helps.

Categories