angular-slider / angularjs-slider

Slider directive for AngularJS 1.X. No dependencies and mobile friendly.
http://angular-slider.github.io/angularjs-slider
MIT License
1.23k stars 498 forks source link

Slider position not set on load #79

Closed rcbgit closed 9 years ago

rcbgit commented 9 years ago

Using angular-fullstack I am setting a slider with the scope value like so:

$scope.sliderValue = 100;

and the markup:

        <rzslider rz-slider-model="sliderValue"
            rz-slider-floor="2"
            rz-slider-hide-limit-labels = "false"
            rz-slider-ceil="100"
            rz-slider-always-show-bar="true"></rzslider>

I am displaying the value of the slider on the page and it is correctly set to 100, but the slider position is stuck at 0 until i click on it, then it jumps up to where it's supposed to be.

soee commented 9 years ago

I can confirm this issue (using Angular 1.4.x).

Update: if i resize my window, slider is updated and renders as it should. My problem might be rleated to the fact that i'm using angular-ui tabs and probably i have to use somehow:

$scope.$broadcast('reCalcViewDimensions');

rcbgit commented 9 years ago

I also see the slider render correctly when I resize.

Still no fix. Let me know if you come up with anything.

Thanks!

soee commented 9 years ago

Hi @rcbgit,

as i mentioned before i am using it inside tabs (ui-bootstrap) so the tab content is loaded when we select tab and because of this the sliders aren't updated as they should i think. What i do is to use tab 'select' attribute to call my custom function:

<tabset>
    <tab select="ctrl.broadcast()">
        <tab-heading>Heading</tab-heading>
        @include('_partials.form_tabs_general')
    </tab>
    ...
</tabset>

and in my controller:

function broadcast() {
    setTimeout(function(){
        $scope.$broadcast('reCalcViewDimensions');
    }, 10);
}

In some cases it is better to use Angular's $timeout service instead of native setTimeout.

bernardmoes commented 9 years ago

I can also confirm this issue. It doesn't work in combination with the following Jquery:

$(document).ready(function () {
            $('.filterButton').click(function (e) {
                e.preventDefault();
                $('.filterButton').removeClass('on');
                $('.filterContent').slideUp('normal');
                if ($(this).next().is(':hidden') == true) {
                    $(this).addClass('on');
                    $(this).next().slideDown('normal');
                }
            });
            $('.filterContent').hide();
        });
bdteo commented 9 years ago

I also experienced exactly what OP described. This repo however seems to be dead anyway.

mansa-dev commented 9 years ago

Yes same issue here. But repo seems to be abandoned

sarbjeetsingh commented 9 years ago

I also got the same issue, i used setTimeout(function(){ $scope.$broadcast('reCalcViewDimensions'); },500)

ValentinH commented 9 years ago

Indeed, using $scope.$broadcast('reCalcViewDimensions'); is the solution. This problem is due that when the slider is instantiated, the view is not visible and so it cannot be rendered properly.

This particular problem with tabs is mentionned here: https://github.com/rzajac/angularjs-slider#slider-events . I have also experienced the issue when using a slider inside a angular-ui dropdown.

aphanor commented 9 years ago

Hey guys, I am having the same issue and I tried adding $scope.$broadcast('reCalcViewDimensions'); but it didn't work. Here is live working example:

http://ec2-52-16-54-212.eu-west-1.compute.amazonaws.com/test.html

The slider is on page "2".

Am I doing anything wrong?

ValentinH commented 9 years ago

Please provide a Fiddle that present the strict minimum of your problem. I don't want to go visiting a random page which can contain anything (virus?)...

aphanor commented 9 years ago

Sure, here is an example on Codepen: http://codepen.io/anon/pen/QbJmja

ValentinH commented 9 years ago

There you go: http://codepen.io/ValentinH/pen/yNQKXR?editors=001

You had several Angular-related problem:

Finally, in your example, it also works without wrapping the $scope.$broadcast('reCalcViewDimensions') with $timeout but it depends on the step plugin sequencing. To be sure that it is always called after the view is shown, use $timeout so the broadcast is called in the next JS loop.

aphanor commented 9 years ago

Awesome, thanks a lot for your help, it's much appreciated!

gpolyn commented 9 years ago

Per the OP's use context, and attempting the fix proposed from Jul 29, this still doesn't work.

Failing an example with tabs, I warn others about this integration!

ValentinH commented 9 years ago

Since I'm in a good mood today, there is your example: Slider inside Angular UI tabs: http://jsfiddle.net/7w755fLv/

I'm adding it to the doc...

gpolyn commented 9 years ago

Yes, that does better address it, though the rendering is triggered by tab select and I think I notice the slider's correcting action, visually.

Based on review of Angular-UI Bootstrap tab issues, I might expect challenges for the embedding of any directive in tab content panes. Therefore, my proposal to anyone (perhaps it is already familiar to most) is to confirm their chosen tab directive works with any directives planned for use in tab panes.

ValentinH commented 9 years ago

You will get issues with any widgets that show/hide content dynamically such as tabs, popover or even ng-show. The problem is that the directive you place inside the content, such as this slider, does not have an efficient way to detect when it becomes visible. So if this directive needs to compute the width/height/position of its parent, you will need to trigger a refresh event manually.

pushpendra18 commented 9 years ago

Hi All,

I have faced the same issue inside accordion my slider not initializing. Finally ValentinH solution guide me in right path. Below is the code.

Calling refreshSlider() in ng-click of the accordion div .

HTML:

<form name="myform">
    <div class="panel-group flatPannels filterGroup" id="accordion">
        <div class="panel panel-default filterStyle" ng-click="refreshSlider()">
            <div class="panel-heading">
                <a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion" data-target="#collapseFour">
                    <h4 class="panel-title">  myslider<i class="indicator glyphicon glyphicon-chevron-down pull-right"></i></h4>
                </a>
            </div>
            <div id="collapseFour" class="panel-collapse collapse">
                <div class="panel-body">
                    <label class="title" ></label>
                    <div class="sliderInputWrapepr">
                        <input type="number"
                               placeholder="{{ 'enter'  }}"
                               ng-change="chklim($event)"
                               ng-minlength="1"
                               ng-maxlength="3"
                               ng-min="aslider.floor"
                               ng-max="aslider.ceil"
                               name="inputvalMax" class="sliderinput" ng-class="{'err-txtbox':!searchFilterForm.inputvalMax.$valid}" ng-model="aslider.value1" required /><br />
                    </div>
                    <rzslider rz-slider-floor="aslider.floor"
                              rz-slider-ceil="aslider.ceil"
                              rz-slider-model="aslider.value"
                              rz-slider-step="1"
                              rz-slider-always-show-bar="true"
                              rz-slider-tpl-url="rzSliderTpl.html"
                              rz-slider-on-change="searchval();"></rzslider>
                </div>
            </div>
        </div>           
    </div>
</form>

Angular:

 $scope.refreshSlider = function () {
    $timeout(function () {
        $scope.$broadcast('rzSliderForceRender');
    });
};
Luddinus commented 8 years ago

With ng-if works, not with ng-show

matortheeternal commented 8 years ago

@Luddinus ng-if works but it doesn't maintain slider values after you hide and show it again.

ValentinH commented 8 years ago

If the slider is inside a div toggled with ng-if, it is destroyed on each hide: this is normal since ng-if destroys its content.

You need to save the slider value in the parent's scope then or in a service.

mjknight50 commented 8 years ago

Hi Valentin, I have the same issue if you wouldn't mind taking a look, please?

https://jsfiddle.net/mjknight50/hmap4qj7/

I have tried all of the suggestions I have seen you post so far, but the initial slider position isn't setting correctly until I resize the screen or until I click on the slider.

ValentinH commented 8 years ago

@mjknight50 You need to send the following event when the slider becomes visible:

$scope.$broadcast('rzSliderForceRender');

I can't really help more because your example is complex and generating a lot of errors that are not linked to the slider.

mjknight50 commented 8 years ago

Thanks Valentin... I added this, which fixed it:

  angular.element(document).ready(function () {
        $scope.$broadcast('rzSliderForceRender');
    });
appernetic commented 8 years ago

Same problem here, I have to try this solution!

2016-04-25 23:13 GMT+02:00 Matthew Knight notifications@github.com:

Thanks Valentin... I added this, which fixed it:

angular.element(document).ready(function () { $scope.$broadcast('rzSliderForceRender'); });

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/angular-slider/angularjs-slider/issues/79#issuecomment-214523887

maknapp commented 8 years ago

For the ng-show and tab problems, I have looked into this further and have a solution that gets rid of any flickering. In angularjs v1.2, the slider did not require a timeout and could be force rendered immediately. This is the breaking commit that defers ng-show until the end of the digest cycle.

So, running force render in post digest instead of JavaScript's next execution cycle (setTimeout) will get rid of any flickering (jsfiddle):

$scope.$$postDigest(function () {
    $scope.$broadcast('rzSliderForceRender');
});

Also, if you want to continue using $setTimeout you should at least stop it from running digest again, since rzSliderForceRender does not require another digest:

$timeout(function () {
    $scope.$broadcast('rzSliderForceRender');
}, 0, false);
ValentinH commented 8 years ago

Thanks, this is really interesting! I'll add it to the README 👍

marie-dk commented 8 years ago

I am using uib-accordion and faced this issue. The solution that works for me, is to watch the is-open variable and render rzSlider on open.

In the slider controller:

$scope.accordion1.status = false;

$scope.$watch('accordion1.status', function(isOpen){
  if (isOpen) {
    $scope.$broadcast('rzSliderForceRender');
    console.log('accordion1 is open');
  }
});

And the accordion:

<uib-accordion close-others="true">
<uib-accordion-group is-open="accordion1.status">
    <uib-accordion-heading>
      <span>Hello world</span>
      </uib-accordion-heading>
      <p>
        <rzslider rz-slider-model="formData.weight"  rz-slider-options="wslider"></rzslider>
       </p>
     </uib-accordion-group>
</uib-accordion>

EDITED: Changed $rootScope to $scope according to ValentinH's comment.

ValentinH commented 8 years ago

You probably don't need to broadcast on the whole $rootscope, $scope.$broadcast might be enough ;)

Dreamerpro commented 8 years ago

I got over this issue by increasing timeout delay to above 170ms. $timeout(function () { $scope.$broadcast('rzSliderForceRender'); },170); I think this is the rendering time taken in my case.

ValentinH commented 8 years ago

The issue is that the rendering time is browser dependant so it might be more on other browser/devices..

niqt commented 8 years ago

I tried any solutions but in uib-tab and uib-tabset, i have always the problem

ValentinH commented 8 years ago

Demo please. Btw there is an example of slider in uib-tab on the website...

niqt commented 8 years ago

Sorry but i in the demo find tab and tabset doesn't see ui-tab and ui-tabset did saw in wrong place?

ValentinH commented 8 years ago

This is just because the demo use on old version of ui-bootstrap where the uib- prefix wasn't mandatory. But the demo shows how to use uib-bootstrap tabs

RogerBrad commented 7 years ago

Thank you for your help. Used this as described in the fiddle: http://jsfiddle.net/8zg6rrn2/1/

In the controller js: var vm = this; vm.refreshSlider = function () { $scope.$$postDigest(function () { $scope.$broadcast('rzSliderForceRender'); }); };

Called it from the ng-show function also in the controller js:

vm.refreshSlider();

marcinn commented 7 years ago

$postDigest nor $broadcast() workarounds does not work for me. I'll try to provide fiddle someday.
No chances to make corrent rendering without such tricks?

ValentinH commented 7 years ago

Unfortunately no, the library can't know when it become visible (or at least not without doing some dirty-checking) so you have to tell it (I usually use $broadcast inside a $ timeout).

marcinn commented 7 years ago

Thanks. I've double checked callback and found a typo. Sorry for disturbing.

marcinn commented 7 years ago

Unfortunatelly there are too many use cases, where refreshing is required. I have a controller which gets an event probably before rendering. It is hard to know when element becomes visible (rendered by browser engine). Maybe you can control it within a directive, but a view controller can't do that without checking DOM elements directly. This makes using the slider very hard and time-consuming. You should find other solution. Just my 5cents.

ValentinH commented 7 years ago

A solution like this: http://stackoverflow.com/a/31085644/1713469 could be doable but it's very heavy since that means angular will check the dom at each $digest iteration! Also this answer: http://stackoverflow.com/a/1462510/1713469 summarizes what I have in mind... Your logic should be predictable so you should always know if the slider container is visible.

marcinn commented 7 years ago

I'm setting scope var to make container visible and directly after that I'm calling refresh event. It does not work probably due some race condition. Unfortunatelly I have no time to dig this issue today.

rsrikanth080 commented 7 years ago

HI! I am using rzslider with controllerAs syntax.

$timeout(function () {
      $scope.$broadcast('rzSliderForceRender');
    }, 10);

This doesnt work. how can i make it work with controllerAs syntax.

ValentinH commented 7 years ago

Please provide a demo showing the issue. There is no reason that using controllerAs syntax could be a cause of this issue.

mjknight50 commented 7 years ago

@rsrikanth080 I am using controllerAs with no problem. As @ValentinH said, if you have a more complete example, it would help.

Here is how I am doing that same block you listed:

//in theory, only one of these should be needed, to force the render, but both are needed in my testing

$timeout(function () { $scope.$broadcast('rzSliderForceRender'); }, 170);

angular.element(document).ready(function () {
    $scope.$broadcast('rzSliderForceRender');
});
ValentinH commented 7 years ago

When do you call $timeout? BTW, we need code to understand what you do. The best so we can help you would be to create a JSFiddle only showing the issue and the code for it.

mjknight50 commented 7 years ago

@rsrikanth080 - Please be considerate of our time. Searching through your source code to help you isn't ideal. A JSFiddle would be better and would probably also help you by isolating the issue.

ValentinH commented 7 years ago

Please, I won't help you if you don't provide materials! I'm not supposed to go and read all your code, people are are contributing on their free time. If you want enterprise support, then pay somebody for that.

ValentinH commented 7 years ago

However, your issue is probably due to the fact the you must call rzSliderForceRender after your popup is shown (as done on the uib-modal demo on our demo page).

mjknight50 commented 7 years ago

I agree with @ValentinH; the issue is that when your shopService comes back with prices, you must then call rzSliderForceRender to reinitialize the slider. You can use my sample code from above to do this rendering.