JQueryUI Sortable не работает при использовании пользовательского компонента с Angular2

Моя цель - позволить пользователям сортировать список команд. Я разрабатываю свое приложение, используя Angular2/Typescript.

Поэтому я искал библиотеки на основе angular2, которые могут обеспечить сортируемую функциональность, аналогичную JQueryUI Sortable, но не смогли найти много.

Я наткнулся на этот пост, который демонстрировал, как интегрировать JQuery с angular2. Используя планку, предоставленную в одном из решений для этого поста, я мог разработать сортируемое поведение с angular2. Посмотри на это. Это работает, как ожидалось.

@Component({
  selector: 'my-app',
  directives: [SMSortable],
  providers: [],
  template: `
    <div>
      <p>This is a list that can be sorted </p>
      <div sm-sortable>
        <p>Item 1</p>
        <p>Item 2</p>
        <p>Item 3</p>
      </div>
    </div>
  `
})
export class App {
  constructor() {
    this.name = 'Angular2'
  }
}

Идея состояла в том, чтобы определить директиву, которая применила бы сортируемое поведение к нативному элементу с помощью API JQueryUI sortable (). А затем используйте директиву в шаблоне компонента.

@Directive({
  selector: "[sm-sortable]"
})
export class SMSortable{

    constructor(el: ElementRef) {
        jQuery(el.nativeElement).sortable( {
              start: function(event, ui) {
                  console.log("Old position: " + ui.item.index());
              },
              stop: function(event, ui) {
                  console.log("New position: " + ui.item.index());
              }
        });
    }
}

Это хорошо работает, когда в шаблоне компонента есть все нативные элементы. Но если мой шаблон имеет пользовательские компоненты angular2, это перестает работать.

Вижу этот неработающий отврат.

@Component ({
  selector: 'sm-cmd',
  template: '<ng-content></ng-content>'
})
export class SMCommand {

}

@Component({
  selector: 'my-app',
  directives: [SMSortable, SMCommand],
  providers: [],
  template: `
    <div>
      <p>This is a list that can be sorted </p>
      <div sm-sortable>
        <sm-cmd><p>Item 1</p></sm-cmd>
        <sm-cmd><p>Item 2</p></sm-cmd>
        <sm-cmd><p>Item 3</p></sm-cmd>
      </div>
    </div>
  `
})
export class App {

}

В этом случае я могу перетащить элемент, но не могу его уронить. Перемещенный элемент возвращается в исходное положение. Я добавил console.log, чтобы увидеть индекс элемента при запуске и остановку события во время сортировки. Значение остается тем же.

Я не могу дальше отлаживать это. Может ли кто-нибудь внести свой вклад в это?

1 ответ

Решение

Проблема на самом деле очень проста: поскольку вы используете пользовательский элемент sm-cmd браузер не знает, какую модель рендеринга использовать (блочную или встроенную). По умолчанию применяется встроенный, что приводит к коллизии с точки зрения размеров элемента, потому что у вас есть уровень блока p внутри встроенный sm-cmd, Таким образом, браузер не рассчитывает размеры блока правильно.

Итак, решение - это простое правило CSS:

sm-cmd {display: block;}

Также убедитесь, что вы инициализируете плагин jQuery в хуке ngAfterViewInit:

@Directive({
  selector: "[sm-sortable]"
})
export class SMSortable{

  constructor(private el: ElementRef) {}

  ngAfterViewInit() {
      jQuery(this.el.nativeElement).sortable( {
            start: function(event, ui) {
                console.log("Old position: " + ui.item.index());
            },
            stop: function(event, ui) {
                console.log("New position: " + ui.item.index());
            }
      });
  }
}

Демонстрация: http://plnkr.co/edit/QEd9wozXSZlqT07qr51h?p=preview

Другие вопросы по тегам