How to scrollTop a div whose content is managed by AngularDart?

前端 未结 3 2006
忘掉有多难
忘掉有多难 2021-01-21 13:56

I have a div holding some chat history. I would like for the div content to scroll when it becomes full. I have this working using jQuery in another p

相关标签:
3条回答
  • 2021-01-21 14:19

    If you're using an AngularDart component you can inject the shadowdom then select an element inside it to focus on. Didnt find a way of getting the container of the shadowdom.

    new Future.delayed(new Duration(milliseconds: 300), () {
      var rowElement = _shadowRoot.querySelector('.step-container');
      if (rowElement != null ) {
        rowElement.scrollIntoView(ScrollAlignment.TOP);
      }
    });
    

    ShadowDom.host might work, though its currently marked as experimental.

    0 讨论(0)
  • 2021-01-21 14:26

    EDIT

    I published a package containing this directive: http://pub.dartlang.org/packages/bwu_angular
    -------

    I would create a Directive/Decorator like NgEventDirective but for the resize event and add it to your div. In the event handler you set your scrollTop property.

    I found contradictory info about the resize event.

    • DART - Resize div element event says it is available everywhere
    • Onresize for div elements? is a workaround for browsers that don't support this event.

    • another page covering this topic: http://marcj.github.io/css-element-queries/

    I tried to create an Angular implementation for the 'workaround' (2nd link) but run into this issue https://code.google.com/p/dart/issues/detail?id=18062 which contains info about a workaround but I didn't yet find time to implement it.

    EDIT

    I checked my attempt and it worked in Dartium with the version I downloaded today (Dart VM version: 1.4.0-dev.4.0 (Thu May 1 04:06:09 2014) on "linux_x64"). I haven't tried in other version since I created the issue.

    (The code should be improved to make the directive more generic - the event method should be assignable by an attribute not hardcoded)

    index.html

    <!DOCTYPE html>
    <html ng-app>
      <head>
        <script src="packages/web_components/platform.js"></script>
        <style>
          .resize-triggers {
                  visibility: hidden;
          }
    
          .resize-triggers, .resize-triggers > div, .contract-trigger:before {
            content: " ";
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            height: 100%;
            width: 100%;
            overflow: hidden;
          }
    
          .resize-triggers > div {
            background: #eee;
            overflow: auto;
          }
    
          .contract-trigger:before {
            width: 200%;
            height: 200%;
          }
        </style>
        <style>
          #my_element {
            height: 200px;
            overflow: scroll;
          }
        </style>
      </head>
      <body ng-cloak>
        <div>
          <div id="my_element"  style="border: 1px solid blue;">
            <div id='my_sizable' ng-observe-size></div>
          </div>
        </div>
    
        <script type="application/dart" src="index.dart"></script>
        <script type="text/javascript" src="packages/browser/dart.js"></script>
    
      </body>
    </html>
    

    index.dart

    library angular_observe_resize.main;
    
    import 'dart:async' as async;
    import 'dart:html' as dom;
    import 'package:angular/angular.dart' as ng;
    import 'package:angular/application_factory.dart' as ngaf;
    
    // see https://stackoverflow.com/questions/19329530
    // and this bug https://code.google.com/p/dart/issues/detail?id=18062
    // source from http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/
    
    @ng.Decorator(selector: '[ng-observe-size]')
    class NgObserveSizeDirective implements ng.AttachAware, ng.DetachAware {
      dom.Element _element;
      bool _hasAttacheEvent;
    
      NgObserveSizeDirective(this._element);
    
      void onSizeChange(dom.Event e) {
        _element.parent.scrollTop = _element.scrollHeight;
      }
    
      dom.HtmlElement _triggers;
    
      void resetTriggers() {
        var expand = _triggers.children[0];
        var contract = _triggers.children[_triggers.children.length - 1];
        var expandChild = expand.children[0];
        contract.scrollLeft = contract.scrollWidth;
        contract.scrollTop = contract.scrollHeight;
        expandChild.style.width = '${expand.offsetWidth + 1}px';
        expandChild.style.height = '${expand.offsetHeight + 1}px';
        expand.scrollLeft = expand.scrollWidth;
        expand.scrollTop = expand.scrollHeight;
      }
    
      int _resizeLastWidth;
      int _resizeLastHeight;
    
      bool checkTriggers() {
        return _element.offsetWidth != _resizeLastWidth ||
            _element.offsetHeight != _resizeLastHeight;
      }
    
      int _resizeRaf;
    
    
      void scrollListener(dom.Event e) {
        resetTriggers();
        if(_resizeRaf != null) {
          dom.window.cancelAnimationFrame(_resizeRaf);
        }
        _resizeRaf = dom.window.requestAnimationFrame((num highResTime){
          if(checkTriggers()) {
            _resizeLastWidth = _element.offsetWidth;
            _resizeLastHeight = _element.offsetHeight;
            onSizeChange(e);
          }
        });
      }
    
      @override
      void attach() {
        if(_element.getComputedStyle().position == 'static') {
          _element.style.position = 'relative';
        }
    
        _triggers = new dom.DivElement()
          ..classes.add('resize-triggers')
          ..append(new dom.DivElement()..classes.add('expand-trigger')..append(new dom.DivElement()))
          ..append(new dom.DivElement()..classes.add('contract-trigger'));
       _element.append(_triggers);
    
        new async.Future.delayed(new Duration(seconds: 1), () {
          //_triggers = _element.children[_element.children.length - 1];
          resetTriggers();
    
          dom.Element.scrollEvent.forTarget(_element, useCapture: true).listen(scrollListener);
        });
      }
    
      @override
      void detach() {
        _triggers.remove();
      }
    }
    
    class MyAppModule extends ng.Module {
      MyAppModule() {
        type(NgObserveSizeDirective);
      }
    }
    
    main() {
      print('main');
      ngaf.applicationFactory().addModule(new MyAppModule()).run();
    
      new async.Timer.periodic(new Duration(seconds: 1), (t) {
        var elt = (dom.querySelector('#my_sizable') as dom.HtmlElement);
        elt.append(new dom.Element.html('<div>${new DateTime.now()}</div>'));
      });
    }
    
    0 讨论(0)
  • 2021-01-21 14:40

    For the first issue you can use Timer.run to defer the scroll execution :

    Timer.run(() => elt.scrollTop = elt.scrollHeight);
    

    For the second issue you can inject the Element managed by your controller and use querySelector on it :

    MyController(Element e) : elt = e.querySelector('.chatHistory');
    
    0 讨论(0)
提交回复
热议问题