I am currently working on a progress bar with jQuery that changes the inner progress bar according to checkboxes.
The script below works quite nicely except for the fact that when I reload the page, the progress bar is empty and the checkboxes are still activated.
This is probably due to the function not counting the number of checked checkboxes but uses the function checkbox.change() to start calculating.
My question now is how to configurate the script in order to update the progress bar even on page reload.
Thanks a lot in advance!
JQuery Script:
$( document ).ready(function() {
var checkbox = $(":checkbox"),
checkbox_length = checkbox.length;
checkbox.change(function () {
var that = $(this),
progress = 0,
checked_length = 0;
if(that.is(':last-child')) {
that.siblings().attr('checked', true);
}
checked_length = $(":checkbox:checked").length;
progress = Math.round(checked_length / checkbox_length * 100);
$('.bar').animate({'width' : progress + '%'}, 400);
$(".progresstext").html(progress + '%');
$.cookie('cookieProcessLevelProgress', progress, { expires: 7, path: '/' });
});
});
HTML code:
<div class="meter"><div class="bar"></div></div><span class="progresstext"></span>
I couldn't really figure out a small part of your code, but what I pasted below is a good start... basically put the "setting" of the progress bar into a function (DRY) and then call it on page load, and on checkbox change :)
function setProgress( $checkboxes ) {
var chk_length = $checkboxes.filter(":checked").length;
var progress = Math.round(chk_length / $checkboxes.length * 100);
$('.bar').animate({'width' : progress + '%'}, 400);
$(".progresstext").html(progress + '%');
};
$(function() {
var $checkboxes = $(":checkbox");
setProgress( $checkboxes );
$checkboxes.change(function(e) {
$(this)
.prevAll(":checkbox")
.prop("checked",true)
.end()
.nextAll(":checkbox")
.prop("checked",false);
setProgress( $checkboxes );
});
});
For your information, you can associate HTML5 progress tag instead of associating jQuery with it. Suppose you use the <progress> tag, like <progress value="6" max="10"> and then update the inner parameter using basic JavaScript. For me, the code looks somewhat like this:
<div id="content">
<progress value="2" max="10">
</div>
The last bit is onClick of checkbox, the value of x gets updated from 2 to 3, using x++. Next update the code using document.getElementById("content").innerHTML and that's it boom, it should work.
Happy coding.
Related
ORIGINAL QUESTION:
I am trying to create some javascript to add to a form in Microsoft Dynamics CRM.
I have the following script which I have assigned to the forms onLoad event:
$(document).ready(function () {
if ($('#CheckBox1').is(':checked')) {
$('<div id="div2">Some Data Here</div>').insertAfter("#Div1");
$('#divHeader').height('+=25px');
var newtop = $('#divMain').position().top + 25;
$('#divMain').css('top', newtop + 'px');
}
});
The following is a stripped down version of the forms HTML
<div id="divHeader">
<div id="Div1"></div>
</div>
<div id="divMain"></div>
When the form loads, what should happen is this:
<div id="divHeader">
<div id="Div1"></div>
<div id="Div2">Some Data Here</div>
</div>
<div id="divMain"></div>
That does happen. However, the problem is that the divHeader and divMain do not resize, so the newly added Div2 can't be seen unless the user scrolls down within the divHeader.
If I add an alert:
$(document).ready(function () {
if ($('#CheckBox1').is(':checked')) {
alert("Random alert");
$('<div id="div2">Some Data Here</div>').insertAfter("#Div1");
$('#divHeader').height('+=25px');
var newtop = $('#divMain').position().top + 25;
$('#divMain').css('top', newtop + 'px');
}
});
The whole thing works perfectly. How do I get this to work without the alert?
UPDATE 1:
setTimeout also works instead of using an alert.
$(document).ready(function () {
setTimeout(function () {
if ($('#CheckBox1').is(':checked')) {
$('<div id="div2">Some Data Here</div>').insertAfter("#Div1");
$('#divHeader').height('+=25px');
var newtop = $('#divMain').position().top + 25;
$('#divMain').css('top', newtop + 'px');
}
}, 5000);
});
So it seems $(document).ready doesn't seem to do it's job properly. In both cases alert or setTimeout, the form gets extra time to finish loading before the div tags are resized.
It is entirely unsupported to do DOM manipulations in Dynamics CRM. See Do Not Access the DOM.
You will instead need to use supported methods of manipulating the form (i.e. Xrm.Page). While it is not possible to dynamically add/remove content on a CRM-form, you can show and hide elements. As I understand it, you are trying to show some content if a boolean field (presented as a checkbox) on the form is true.
This can be done by adding the control that you want to show/hide to your form (that control can either be one of the standard CRM-fields or a custom web resource, depending on your requirements). You would then write a bit of JavaScript to show/hide the control in question when your boolean attribute changes its value:
function onload() {
Xrm.Page.getAttribute("booleanField").addOnChange(showMoreStuffInHeader);
showMoreStuffInHeader();
}
function showMoreStuffInHeader() {
var visible = Xrm.Page.getAttribute("booleanField").getValue();
Xrm.Page.getControl("someDataHereControl").setVisible(visible);
}
Use Jquery Plugin Wait until element exists Pluging will wait for element to appear in DOM and then fire given handler function.
$(document).ready(function () {
$('#CheckBox1').waitUntilExists(function () { // OR $('#Div1').waitUntilExists(function ()
if ($('#CheckBox1').is(':checked')) {
$('<div id="div2">Some Data Here</div>').insertAfter("#Div1");
$('#divHeader').height('+=25px');
var newtop = $('#divMain').position().top + 25;
$('#divMain').css('top', newtop + 'px');
}
});
});
I'm working on a script to simulate a page change in a Questionnaire I'm building. I figured maybe I could use a bunch of "if" statements to house all the logic but it's not working right, before I go and create separate functions I'd like to know if it's possible to put them all in one single function.
So far this is the script
function pageChange(){
var chng1 = document.getElementById("p1next");
var chng2a = document.getElementById("p2back");
var chng2b = document.getElementById("p2next");
var chng3a = document.getElementById("p3back");
var chng3b = document.getElementById("p3next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
var pg3 = document.getElementById("page03");
if (chng1.click){
pg1.style.display="none";
pg2.style.display="block";
}
if (chng2a.click){
pg1.style.display="block";
pg2.style.display="none";
}
the "p1next, p2back, p2next etc." are IDs I gave the buttons on the pages, which I have in DIVs that I respectively named "page01, page02, page03 etc."
Without the 2nd if statement the script works exactly how I want it, it changes the display for "page01" to none and the div for "page02" to block. When I add the second if statement it doesn't work.
The reason I want to do it like this rather than making actual pages is because I don't want the data to get lost when they load another page. Am I on the right track or do I need to create a new function for each page?
Not exactly on the right track, you should use onclick events, instead of if (x.click) like this:
var chng1 = document.getElementById("p1next");
var pg1 = document.getElementById("page01");
var pg2 = document.getElementById("page02");
// Events
chng1.onclick = function(){
pg1.style.display="none";
pg2.style.display="block";
};
This will save your function until the element is clicked and then execute that function. In your case, it is executed on page load, and at that moment the user is not clicking anything.
Why not try something like this:
HTML:
<div class="page" data-pg="1">...</div>
<div class="page" data-pg="2">...</div>
<div class="page" data-pg="3">...</div>
<input id="btnPrev" type="button" value="Prev" />
<input id="btnNext" type="button" value="Next" />
jQuery:
var pageNum = 1;
$(document).ready(function () {
$("#btnPrev").on("click", function () { ChangePage(-1); });
$("#btnNext").on("click", function () { ChangePage(1); });
ChangePage(0);
});
function ChangePage(p) {
$(".page").hide();
pageNum += p;
$(".page[data-pg='" + p + "']").show();
$("#btnPrev").removeAttr("disabled");
$("#btnNext").removeAttr("disabled");
if (pageNum === 1) $("#btnPrev").attr("disabled", "disabled");
if (pageNum === $(".page").length) $("#btnNext").attr("disabled", "disabled");
}
That way you can easily grow your number of pages without changing the script. My apologies by the way for doing this in jQuery.
Update:
Have a lot of time on my hands today and have not coded for while using vanilla Javascript. Here's the version of the code using plain js: https://jsfiddle.net/hhnbz9p2/
Pretty sure I know the solution... would write .on('change','load', function(){}
correct? <-- Tested didn't work? so I am up to your solutions :)
Sushanth -- && adeneo both came up with great solutions, this is a good lesson in optimizing code... It's gonna be hard to choose which answer to go with, but I know this is going to help me rethink how I write... I dont know what I do without this forum, id have to learn this stuff in college.
This is purely a question out of curiosity and bettering my skills, as well as giving you guys a chance to display your knowledge on jQuery. Also to prevent any sloppy writing.
I have a radio based switch box, the markup looks like this, the id's and on/off values are generated by the values in my array with PHP...
<span class="toggle-bg">//This color is the background of the toggle, I need jQuery to change this color based on the state on/off
<input type="radio" value="on" id="_moon_page_header_area1" name="_moon_page_header_area">//this is my on value generated by the array
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">// I create this input because I have multiple checkboxes that have the ID _moon_ARRAYVALUE_area1
<input type="radio" value="off" id="_moon_page_header_area2" name="_moon_page_header_area">// off value
<input type="hidden" value="_moon_page_header_area" class="switch-id-value">//_moon_ARRAYVALUE_area2
<span class="switch"></span>// the switch button that changes
</span>
Hope that makes sense and the comments are clear
Here is the jQuery
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.hide()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.show()
}
$('.toggle-bg').change(function () {
var value = $('.toggle-bg input.switch-id-value').val()
var moon1 = $('#'+value+'1').is(':checked');
var moon2 = $('#'+value+'2').is(':checked');
var static_slide = $('._moon_staticarea_height');
var toggle = $('.toggle-bg');
if(moon1){
toggle.css({'background-color': '#46b692'});
static_slide.slideUp()
} else
if (moon2){
toggle.css({'background-color': '#333'});
static_slide.slideDown()
}
});
it looks longer than it really is, its just repeating it self, one is on load so that it gives the correct color on load of the page, and then inside the change function we need to change colors..
How do I write it so I only have to use variables one time (so its cleaner) is there a better way to optimize it... Just NOW thinking after writing this I could put it in one function .on('load', 'change', function() {}
I just now thought of that, but I wrote all this so I am going to see what others think...
You'd do that by having the function in the change event handler, and on the end you chain on a trigger('change') to make it work on pageload :
$('.toggle-bg').on('change', function () {
var value = $('.toggle-bg input.switch-id-value').val(),
moon1 = $('#' + value + '1').is(':checked'),
slider = $('._moon_staticarea_height'),
toggle = $('.toggle-bg');
toggle.css('background-color', (moon1 ? '#46b692' : '#333'));
slider[moon1?'slideUp':'slideDown']();
}).trigger('change');
As radiobuttons can't be unchecked, it's either moon1 or moon2, which means checking one of them should be enough.
.on('change','load',
supposed to be
// Remove the comma separator if you want to bind the same handler to
// multiple events.
.on('change load',
And you can remove the one separately written out and enclose it in a function (if multiple instances of the class toggle-bg)
or just trigger the change event.(If there is a single instance of a class)
This will just run the same functionality when the page loads.
var toggle = $('.toggle-bg');
toggle.change(function () {
var value = $('input.switch-id-value', this).val(),
moon1 = $('#' + value + '1').is(':checked'),
moon2 = $('#' + value + '2').is(':checked'),
static_slide = $('._moon_staticarea_height');
if (moon1) {
toggle.css({
'background-color': '#46b692'
});
static_slide.slideUp()
} else if (moon2) {
toggle.css({
'background-color': '#333'
});
static_slide.slideDown()
}
}).change();
I have problems for insert dynamic id into function of JavaScript the code:
$('#scroll-up1, #scroll-down1').bind({ ..............
In this example I need the function to take values of id I send across the function
$('#scroll-up+id, #scroll-down+id').bind({ ..............
The problem it´s the quotes as " or ' no works for me and I can´t use right for function works fine , this script let me scroll text ok but only problem with this because no let me send values right from id of function.
EDIT FOR ME FOR PUT ALL CODE : .....
PHP AND HTML CODE
<?php
$fil_comments=file("comments.txt");
for ($i=0;$i<sizeof($fil_comments);$i++)
{
$line=explode("~",$fil_comments[$i]);
if ($i%2==0)
{
$back=1;
}
else
{
$back=2;
}
?>
<li>
<div id="web_comment_<?php echo $back?>">
<div id="web_comment_name"><?php echo $line[0];?></div>
<div class="web_comment_texto" id="scroll<?php echo $i;?>"><?php echo $line[1];?></div>
<div class="web_comment_arrow" style="margin-left:260px;" id="scroll-down<?php echo $i;?>"><img src="imagenes/comments/arrow_up.png"></div>
<div class="web_comment_arrow" style="margin-left:288px;" id="scroll-up<?php echo $i;?>"><img src="imagenes/comments/arrow_down.png"></div>
</div>
</li>
<script>
scroll_diver(<?php echo $i;?>);
</script>
<?
}
?>
FUNCTION OF JAVASCRIPT CODE
<script type="text/javascript">
function scroll_diver(id)
{
$(function() {
var ele = $('#scroll'+id);
var speed = 30, scroll = 5, scrolling;
$('#scroll-up'+id).mouseenter(function() {
// Scroll the element up
scrolling = window.setInterval(function() {
ele.scrollTop( ele.scrollTop() - scroll );
}, speed);
});
$('#scroll-down'+id).mouseenter(function() {
// Scroll the element down
scrolling = window.setInterval(function() {
ele.scrollTop( ele.scrollTop() + scroll );
}, speed);
});
//var a='#scroll-up'+id;
//var b='#scroll-down'+id;
var a='#scroll-up'+id;
var b='#scroll-down'+id;
//$('a,b').bind({
//$('#scroll-up1, #scroll-down1').bind({
//$('#scroll-up'+id+',#scroll-down'+id)
/// THE PROBLEM HERE !!!
$('#scroll-up'+id+', #scroll-down '+id).bind({
click: function(e) {
// Prevent the default click action
e.preventDefault();
},
mouseleave: function() {
if (scrolling) {
window.clearInterval(scrolling);
scrolling = false;
}
}
});
});
}
</script>
Basically the problem it´s in the line of JavaScript function for send id, if you see the PHP code, I use bucle for for create scrolling tips with informations and in each I can scroll his content, for this I call function into the bucle with:
<script>
scroll_diver(<?php echo $i;?>);
</script>
But in this line no send right information for works ok, if I use out bucle for one specific id, works ok , with this works yes but scroll up and down crazy fast , and the controls no works fine.
Then you need to look at something like this:
$('#scroll-up' + id + ', #scroll-down' + id).bind({ ..............
As a commentor mentioned, jQuery selectors are simply strings. You can put them together as you see fit. In this case, I'm concatenating the id (which for simplest examples, I'm assuming is a number or other unique identifier) to the #scroll-up selector, so if your id was "1", you would end up with a string, effectively, that looks like:
'#scroll-up1, #scroll-down1'
after the string concatenation occurs.
Also, it might be worth noting that you'd probably get better bang for your buck if you simply gave both objects the same class, then inside your binding function, work out which item called and perform your scrolling appropriately.
So, if you had:
<div class="container">
<div id="scroll-up1" class="scroller"><!-- and code --></div>
<div id="scroll-down1" class="scroller"><!-- and code --></div>
</div>
then your javascript could look like this, avoiding the need for concatenation:
$('.container').on("mouseover",'.scroller', function(){
var thisId = $(this).attr("id");
if(thisId == "scroll-up1"){
// do your up-scroll
} else if(thisId == "scroll-down1") {
// do your down-scroll
}
});
Mind you, that uses .on(), which is preferred over .bind(), but the idea is to handle it based on a common class, rather than having to modify your selector every time you go to bind your event handler for those items.
Recommended solution: use CLASS NAMES for COMMON FEATURES
$('.scroll-up, .scroll-down').bind({
or even:
$('.scroll').bind({
var id = 38;
$('#scroll-up' + id + ', #scroll-down' + id).bind({ ..............
I'm trying to get JScrollPane to reinitialize on expand/collapse of my accordion found here. You can demo the accordion by clicking on one of the parents (Stone Tiles, Stone Sinks, Stone Wall Clading, etc).
Right now I set it as a click event using the following JQuery...
var pane = $('.menuwrap')
pane.jScrollPane();
var api = pane.data('jsp');
var i = 1;
$("ul#widget-collapscat-5-top > li.collapsing").click(function() {
$(this).delay(3000);
api.reinitialise();
});
It seems to work when you click the parent the second time, but not the first. I have no idea why but I went into trying to edit the JS for the accordion so that I can add this function when the collapse is complete (as opposed to trying to do this click workaround). The collapse JS can be viewed here.
I tried to add the JS for the reinitialize function here, but I think I'm not doing something properly.
May you point me in the right direction?
Thanks!
The api.reinitialise() is working properly. What is happening is that it updates the size when you click, and at this moment the element is not expanded yet. You may notice that if you expand, colapse and expand again the same section, nothing happens. But if you expand one and then click another one, the ScrollPane will adjust to the size of the first expanded element.
You can solve this with events: place $(this).trigger('colapseComplete') when the colapse ends. Then you can use:
//Listening to the colapseComplete event we triggered above
$("#widget-collapscat-5-top > li.collapsing").on('colapseComplete', function() {
api.reinitialise();
});
Maybe you can alter the addExpandCollapse function to call the reinitialise function at the end of each of its click actions this way :
function addExpandCollapse(id, expandSym, collapseSym, accordion) {
jQuery('#' + id + ' .expand').live('click', function() {
if (accordion==1) {
var theDiv = jQuery(this).parent().parent().find('span.collapse').parent().find('div');
jQuery(theDiv).hide('normal');
jQuery(this).parent().parent().find('span.collapse').removeClass('collapse').addClass('expand');
createCookie(theDiv.attr('id'), 0, 7);
}
jQuery('#' + id + ' .expand .sym').html(expandSym);
expandCat(this, expandSym, collapseSym);
api.reinitialise(); // HERE
return false;
});
jQuery('#' + id + ' .collapse').live('click', function() {
collapseCat(this, expandSym, collapseSym);
api.reinitialise(); // and HERE
return false;
});
}
and to be on a safer side, make sure you have the var api = pane.data('jsp'); line before the above piece of code anywhere in the file.