Can anyone inform me how to maintain the jquery accordion active state panel when changing pages. Ideally i would like to change in the code-behind however really happy to just get it working.
developing in asp.net 3.5
Hope this helps
Thanks
Example here. If you select one of the accordion headers then refresh the page the last accordian panel you clicked is opened by default
I see this as a pure client responsibility. I would store the information in a cookie plugin here which you can read and pass to the accordion constructor.
I would prefer this over passing values to and from the server for no real benefit.
Something along these lines
//get persisted active accoridan index
var activeIndex = $.cookie('accordianActiveIndex');
//guard code here to check you have a valid activeIndex...
$('.selector').accordion({
active: activeIndex,
change: function(event, ui) {
//set cookie here to new active header (index)
$.cookie('accordianActiveIndex', ui.newHeader.prevAll().length)
}
});
For anyone with a similar problem getting cookies to work with jQuery UI Accordion, I've solved it by adding one line to redsquare's code.
The cookie value activeIndex needs to be parsed as an integer:
//get persisted active accoridan index
var activeIndex = $.cookie('accordianActiveIndex');
activeIndex = parseInt(activeIndex, 10);
//guard code here to check you have a valid activeIndex...
$('.selector').accordion({
active: activeIndex,
change: function(event, ui) {
//set cookie here to new active header (index)
$.cookie('accordianActiveIndex', ui.newHeader.prevAll().length)
}
});
And here's another way to save UI Accordion state using the cookie.js plugin:
(source)
var accordion = $("#accordion");
var index = $.cookie("accordion");
var active;
if (index !== null) {
active = accordion.find("h3:eq(" + index + ")");
} else {
active = 0
}
accordion.accordion({
header: "h3",
event: "click hoverintent",
active: active,
change: function(event, ui) {
var index = $(this).find("h3").index ( ui.newHeader[0] );
$.cookie("accordion", index, {
path: "/"
});
},
autoHeight: false
});
I Just use
$( ".selector" ).accordion({ navigation: true });
that maintains the status of the selected option
Related
I am using pnotify and loading callback function to show a notification when the fullcalendar plugin has loaded all events.
loading:function(isLoading, view){
if (isLoading === false){
new PNotify({
title:"Finished loading events",
type:'success',
delay: 1000
});
My problems is that when ever I move to different dates it calls loading again so I am left with so many notifications shown on my screen that it becomes very unusable. How can I bypass this? Is there a way to check if a notification is active and just change the text and title of it?
You can add that logic based on the template you're using (check the template docs).
Your code would be something like
loading:function(isLoading, view){
var exists = false;
$(".ui-pnotify-title").each(function() {
if ($(this).html() == 'Finished loading events')
exists = true;
});
if (!exists) {
new PNotify({
title:"Finished loading events",
type:'success',
delay: 1000
});
}
}
It would be better if you could use a specific id or class to detect if the notification is already shown, but this works.
Take a look at the working jsfiddle.
You can just store it in a variable, do your necessary code (like nullable/undefined checks, etc) and call "update()" (here: http://sciactive.com/pnotify/ - for example, find for 'Click Notice' and see the source)
var p = new PNotify({
title: 'Some title',
text: 'Check me out! I\'m a error.',
type: 'error',
icon: 'fa fa-times-circle'
});
// ... code ...
p.update({title: 'My new title'});
I am having issues with Concrete5's Build-In 'User' Property on the composer form for new pages. When clicking "Select User" the page navigates to http://website.com/ccm/system/dialogs/user/search. But that page is completely blank.
When you go into the attributes tab and click "Select User" under "Author" it also has the URL http://website.com/ccm/system/dialogs/user/search, but instead of reopening the page, it launches the user selector within the current page. This, I believe, is accomplished using the following JavaScript:
$(function() {
$("#ccm-user-selector-uID").dialog();
$("#ccm-user-selector-uID").on('click', function() {
var selector = $(this);
ConcreteEvent.unsubscribe('UserSearchDialogSelectUser.core');
ConcreteEvent.subscribe('UserSearchDialogSelectUser.core', function(e, data) {
var par = selector.parent().find('.ccm-summary-selected-item-label'),
pari = selector.parent().find('[name=uID]');
par.html(data.uName);
pari.val(data.uID);
e.stopPropagation();
jQuery.fn.dialog.closeTop();
});
ConcreteEvent.subscribe('UserSearchDialogAfterSelectUser', function(e) {
jQuery.fn.dialog.closeTop();
});
});
});
The 'User' option in the Composer has very similar JavaScript associated with it, replacing only the selectors.
$(function() {
$("#ccm-user-selector-ptComposer[13][user]").dialog();
$("#ccm-user-selector-ptComposer[13][user]").on('click', function() {
var selector = $(this);
ConcreteEvent.unsubscribe('UserSearchDialogSelectUser.core');
ConcreteEvent.subscribe('UserSearchDialogSelectUser.core', function(e, data) {
var par = selector.parent().find('.ccm-summary-selected-item-label'),
pari = selector.parent().find('[name=ptComposer[13][user]]');
par.html(data.uName);
pari.val(data.uID);
e.stopPropagation();
jQuery.fn.dialog.closeTop();
});
ConcreteEvent.subscribe('UserSearchDialogAfterSelectUser', function(e) {
jQuery.fn.dialog.closeTop();
});
});
});
I can't find anything that is keeping the functionality form working as expected on the Composer section, like it does on the Attributes section when creating a new page.
Has anyone else run into this or have any ideas on what might be the problem?
Turns out the issue was related to the two following lines:
$("#ccm-user-selector-ptComposer[13][user]").dialog();
$("#ccm-user-selector-ptComposer[13][user]").on('click', function() {
They aren't valid ID's and thus jQuery couldn't find them. A hacky solution to solve the issue was to replace lines 38 and 39 in concrete/src/Form/Service/Widget/UserSelector.php with
$("[id='ccm-user-selector-{$fieldName}']).dialog();
$("[id='ccm-user-selector-{$fieldName}']).on('click', function() {
Which allows for it to search out any elements that have an ID that matches that string.
I've got a link that I want the user to press. When they press it, the router will go to a certain template and then run Smoothscroll.js code to animate and scroll down to the anchor tag.
//When the user clicks on the link to get to the #contact anchor...
//The code below does not work.
Router.go('index');
$('html,body').animate({
scrollTop: $('#contact').offset().top
}, 1200);
Router.go('index') works just fine.
$('html,body').animate({
scrollTop: $('#contact').offset().top
}, 1200);
Works as well by itself on the index template.
But when I try to run them together, the router goes to index, but the scrolling does not work.
Any idea how I can do this?
EDIT
This is what I have for the latest Meteor 1.0+ and a path like /#contact
Router.route('/', {
name: 'index'
});
Router.onAfterAction(function() {
var self = this;
// always start by resetting scroll to top of the page
$(window).scrollTop(0);
// if there is a hash in the URL, handle it
if (this.params.hash) {
// now this is important : Deps.afterFlush ensures that iron-router rendering
// process has finished inserting the current route template into DOM so we
// can manipulate it via jQuery, if you skip this part the HTML element you
// want to scroll to might not yet be present in the DOM (this is probably
// why your code fails in the first place)
Tracker.afterFlush(function() {
if (typeof $("#" + self.params.hash).offset() != "undefined"){
var scrollTop = $("#" + self.params.hash).offset().top;
$("html,body").animate({
scrollTop: scrollTop
});
}
});
}
});
Unless you're doing something fancy you probably don't want to use Router.go and instead let iron-router manage routing on anchor click as it normally does.
As far as scrolling to an element is concerned, this is the onAfterAction hook I'm using, it supports any route and any hash (/anyroute#anyhash).
Router.onAfterAction(function() {
// always start by resetting scroll to top of the page
$(window).scrollTop(0);
var hash=this.params.hash;
// if there is a hash in the URL, handle it
if (hash) {
// now this is important : Tracker.afterFlush ensures that iron-router
// rendering process has finished inserting the current route template
// into DOM so we can manipulate it via jQuery, if you skip this part
// the HTML element you want to scroll to might not yet be present in
// the DOM (this is probably why your code fails in the first place)
Tracker.afterFlush(function() {
var element=$("#"+hash);
var scrollTop = element.offset().top;
$("html,body").animate({
scrollTop: scrollTop
});
});
}
});
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]);
When I use ajax, I noticed that Jquery effects don't work. The reason is "The new HTML you're adding to the DOM (page) didn't exist when your jquery ran the first time "
another similar question
Therefore, I changed my code to following but still I don't get the jquery effects.
Where I have done the mistake?
Previous code
$("#sendemp").click(function(e) {
e.preventDefault();
var submit_val = $("#searchbox").val();
//alert('submitval is ' + submit_val);
$.ajax( {
type : "POST",
//dataType :"jason",
url : "./wp-admin/admin-ajax.php",
data : {
action : 'employee_pimary_details',
user_name : submit_val
},
success : function(data) {
// alert('hhh');
$('#accordion21').html(data);
// $( "#searchbox" ).autocomplete({
// source: data
// });
}
});
});
New code
$("button").on( "click", "#accordion3",function(){
$.ajax( {
type : "POST",
dataType : "json",
url : "./wp-admin/admin-ajax.php",
data : {
action : 'employee_deatils_search',
user_name : submit_val
},
success : function(data) {
// alert('hhh');
$('#accordion3').html(data);
$("tr:odd").css("background-color", "#F8F8F8");
$("#accordion3").accordion({ heightStyle: "fill", active: 0 });
// $( "#searchbox" ).autocomplete({
// source: data
// });
}
});
} );
I have following submit button
<input type="submit" id="sendemp" value="Search" />
I don't think your click binding is correct, if you want to handle clicks on button inside #accordion3 change it to:
$("#accordion3").on( "click", "button",function(){...});
It is hard to tell without your html, but it looks like in your old code you are replacing the sendemp button. In your new code your event delegation is incorrectly specified. You are applying delegation to a button element (which doens't exist since your sendemp button is an input element).
Apply delegate to something that is the parent of #sendemp like so:
$('body').on('click', '#sendemp', function() {
// your ajax call
});
I could fix the issue, I tried the above solution that is using on method. However, it doesn't make sense to my problem.
As following artical explain I think, Accordion is already instantiated and effects are persistance. When it is called second time, it won't create again since there is already the effects.
Therefore, I needed to destroy it and recreate accordion.
support link
I changed the code on success as follows
success : function(data) {
// alert('hhh');
$('#accordion3').accordion('destroy');
$('#accordion3').html(data);
$("tr:odd").css("background-color", "#F8F8F8");
//$("#accordion3").accordion( "disable" );
$("#accordion3").accordion({ active: 0 });
}
And out of $(document).ready(function() {
I added
$(function() {
$("#accordion3").accordion({
// heightStyle: "fill",
active: 0 });
});