Alexei Darmin
Alexei Darmin

Reputation: 2129

Parent style depends on child's dynamic value

I'm using countUp, which counts up to a number. See demo. I have a set of Bootstrap progress bars that I'd like to animate the number shown and the width of the bar.

Markup:

<div class="progress">
  <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%;">
    <span class="js-countup" data-count="80"></span>%
  </div>
</div>

The numbers animate fine with:

$.each($('.js-countup'), function () {
  var count = $(this).data('count'),
    numAnim = new CountUp(this, 0, count);

  numAnim.start();
});

Now I need to animate the style="width" within progress-bar. How can I make the width dependant on the value in the span.js-countup so as the number increases the width of the parent also increases?

Edit The counted number is applied within the span like so <span class="js-countup" data-count="80">0 to 80</span>%

Edit A hacky solution would be to trigger a CSS3 transition on the bar width of equal duration as the countUp. Although that may work for my exact problem, it wouldn't answer the child/parent dependancy.

Upvotes: 3

Views: 153

Answers (1)

Sabrina
Sabrina

Reputation: 617

I've looked into MutationObserver, setInterval(), etc. and nothing is super elegant or simple enough for what you're doing. If you aren't opposed to adding a jQuery plugin, give jQuery-Watch a try. It watches an element for changes to properties, attributes, HTML, etc.

The following will get you started, but you might want to refine it a smidge. It's a bit jumpy to start:

$(".js-countup").watch({
  properties: "prop_innerHTML",
  watchChildren: true,
  callback: function (data, i) {
    $('.progress-bar').css('width',data.vals[i] + '%');
  }
});  

Removing the initial width on the progress bar helps, but you should set a min-width as per Bootstrap's documentation for progress bar labels so the percentage always has a background.

Here's a fiddle for you, but it won't work in Chrome because I've linked directly to the raw files on GitHub (Firefox and Safari work fine).

Edit: I've updated the fiddle with a min-width of 3em, removed % symbol from the label and passed it into CountUp() as a suffix so you don't have a blank percentage visible on your progress bar. CountUp() now looks like this:

numAnim = new CountUp(this, 0, count, 0, 2.5, { suffix : '%' });

Edit 2: This question has become a bit of an addiction for me. Using your CSS animation approach, you can save yourself some markup by eliminating the countup element entirely and using the aria attributes on your progress bar. Then just set the width of the progress bar to match aria-valuenow when you start your counter.

Updated fiddle.

HTML

<div class="progress">
  <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100">
  </div>
</div>

CSS

.progress-bar {
  min-width: 3em;
  -webkit-transition: width 2.5s ease-in-out;
     -moz-transition: width 2.5s ease-in-out;
       -o-transition: width 2.5s ease-in-out;
          transition: width 2.5s ease-in-out;
}

jQuery

$.each($('.progress-bar'), function () {
  var count = $(this).attr('aria-valuenow'),
    numAnim = new CountUp(this, 0, count, 0, 2.5, { suffix : '%' });
  $(this).css('width', count + '%');
  numAnim.start();
});

Edit 3: countUp.js will throw errors if the values are null or 0. Here's an updated fiddle with some basic error prevention and the addition of a duration data attribute for greater granularity.

Upvotes: 1

Related Questions