【问题标题】:Angular 2 Dragula Model updating incorrectlyAngular 2 Dragula 模型更新不正确
【发布时间】:2016-12-07 00:25:19
【问题描述】:

使用 ng2-dragula。我正在寻找使用新删除的订单更新数据库中每个项目的 orderNumber。

dragulaService.dropModel.subscribe((value) => {
  var drake = dragulaService.find('bag-orders').drake
  var models = drake.models
  console.log(models)
})

它返回的新模型订单不反映包内订单。

TL;DR:有没有人使用 ng2-dragula 在数据库 onDrop 中实现重新排序?

【问题讨论】:

  • 遇到同样的问题,似乎找不到答案。实际上,一旦放下它,我就完全失去了拖动的 DOM 元素。简单地删除 [dragulaModel]='myList' 似乎可以解决这种奇怪的行为(仍然可以拖放 - 但不再可以触发 dragulaService.dropModel 调用)。
  • @DanJ,我看到的只是一个设置场景,与 onDrop 或从 onDrop 返回的模型无关?
  • 抱歉,一定是复制粘贴问题 - 绕着圈子试图找出问题所在。
  • 解决了我的问题,这可能会对您有所帮助。如果没有,请发布更多代码,我可以尝试帮助调试。 stackoverflow.com/a/41048184/362576
  • 问题解决了吗?我在这里没有看到任何可接受的答案。

标签: angular dragula angular-dragula ng2-dragula


【解决方案1】:

如果您希望能够拖动项目(不让它们消失)并触发 dropModel 事件:

  • 将 [dragula] 和 [dragulaModel] 指令放在 父元素 中。 (例如,与将它们放在<li> 中的当前文档相反,您必须将它们放在<ul>

  • 注入dragularService,并在组件的构造函数中:

  • 为包调用dragulaService.setOptions(可以传递一个空字典)。 如果你不调用它,dropModelcallback 不会被触发

  • 订阅 dropModel

结果:

<!--thecomponent.html-->
<h2>Playlists</h2>
<ul [dragula]='"first-bag"' [dragulaModel]='playlists'>
  <li *ngFor="let playlist of playlists">

//Inside the component.ts  
playlists: Playlist[];

constructor(private youtubeService: YoutubeService, private dragulaService: DragulaService) {

    dragulaService.setOptions('first-bag', {})
    dragulaService.dropModel.subscribe((value) => {
      this.onDropModel(value);
    });
}

private onDropModel(args) {
    //Here, this.playlists contains the elements reordered
}

【讨论】:

  • 谢谢,但我已经到了这个阶段——我的问题是 onDrop 返回的对象模型的顺序错误。我相当肯定这是库的限制,因为删除的对象移动到正确的索引,但其他对象仅向下移动,而不是重新排序。这对于找到新的插槽非常有用,但是我需要替换列表中 每个 项目的 orderNumber
  • 这是一个很好的讨论,可能对其他人有所帮助,还包括一个指向 plunk 的链接,该链接显示使用 dropModel 对项目进行排序并在 dropModel 事件触发后捕获正确的顺序。 github.com/valor-software/ng2-dragula/issues/306
  • setOptions 解决了我的问题。
【解决方案2】:

我使用的是 ng2-dragula,但我注意到这很奇怪。我遇到的问题是一样的。服务端调用没有按照拖拽顺序更新数据对象。

我刚刚在 ngDoCheck 生命周期钩子中使用了 if 子句来解决问题。

它在控制台的打印对象中排序。在深入挖掘之后,可以在网络中发现与更新服务器调用一起发送的对象是未更新的对象。

所以,这是因为服务器调用是在数据对象更新之前进行的。

我所做的只是添加一个可以跟踪拖动的全局变量已更新数据对象。

private dropModelUpdated = false;

ngAfterViewInit() {
    // this method only changes a variable to execute a method in ngDoCheck
    this.dragulaService.drop.subscribe((value) => {
      this.dropModelUpdated = true;
    });
}

然后,在 ngDoCheck 生命周期钩子中,

ngDoCheck() {    
    if (this.dropModelUpdated) { // this excutes if this.dropModelUpdated is true only
        const drake = this.dragulaService.find('any_bag_name').drake;
        const models = drake.models;
        this.modelContent.groups = models[0];
        // ...Here... Make the server or DB call to update the model with the changed/sorted order
        this.dropModelUpdated = false; // make sure this is there for the next smooth execution
    }
}

【讨论】:

    【解决方案3】:

    我终于找到了解决办法。 我有一个水平列表。前两个元素是我想忽略的元素,它们都有 ignore CSS 类。所有元素都有item 类。所以标记:

    <ul [dragula]='"foo-list"' class="list">
        <li class="list ignore">a</li>
        <li class="list ignore">b</li>
        <li class="list" *ngFor="let item of getList()" [attr.data-id]="item.id">{{ item.name }}</li>
    </ul>
    

    然后是 TypeScript:

    constructor(private dragulaService: DragulaService) {
        let dragIndex: number, dropIndex: number;
    
        dragulaService.setOptions('foo-list', {
            moves: (el, source, handle, sibling) => !el.classList.contains('ignore'),
            accepts: (el, target, source, sibling) => sibling === null || !sibling.classList.contains('ignore'),
            direction: 'horizontal'
        });
    
        dragulaService.drag.subscribe((value) => {
            // HACK
            let id = Number(value[1].dataset.id);
            if (!!id) {
                dragIndex = _.findIndex(this.getList(), {id: id});
            }
        });
    
        dragulaService.drop.subscribe((value:any[]) => {
            // HACK
            let elementNode = value[2].querySelectorAll('.item:not(.ignore)').item(dragIndex);
            if (elementNode) {
                let id = Number(elementNode.dataset.id);
                if (!!id) {
                    dropIndex = _.findIndex(this.getList(), {id: id});
                }
            }
    
            if (value[2] === value[3]) { // target === source
                if (dragIndex >= 0 && dropIndex >= 0 && dragIndex !== dropIndex) {
                    let temp: any = this.list[dragIndex];
    
                    this.list[dragIndex] = this.list[dropIndex];
                    this.list[dropIndex] = temp;
                }
            }
    
            // Custom code here
        });
    }
    
    getList(): any[] {
        return this.list;
    }
    

    【讨论】:

      【解决方案4】:

      我发现 Marçal 的回答非常有用,甚至对其进行了一些扩展,以将更新发布到我的数据库以更新列表中每个项目(在我的情况下是组织内的联系人)的序列值:

      HTML(容器是联系人的组织。就我而言,联系人不能在组织之间移动):

      <div class="container" [dragula]="'org-' + org.id" [dragulaModel]="org.contacts">
        <nested-contact *ngFor="let contact of org.contacts" [user]="contact" class="contact" [attr.data-id]="contact.id"></nested-contact>
      </div>
      

      JS(在我的联系人服务中,一个 PUT 函数用于更新与我的每个联系人关联的存储序列值,以便他们的订单持续存在):

      contactsIdPut (id, body) {
        let url = '/api/v3/contacts/' + id + '?access_token=' + localStorage.getItem('access_token');
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
      
        return this.http.put(url, body, options)
          .map((response: Response) => {
            return response.json();
          });
      

      }

      JS(在我的组织视图组件中,分别概述拖放时要执行的操作):

      export class nestedOrganizationComponent {
        orgs = [];
        thisOrg: any;
        thisContact: any;
      
        constructor (private _contactService: ContactService, private dragulaService: DragulaService) {
          this._contactService = _contactService;
      
          let dragIndex: any;
          let dropIndex: any;
          let elementNode: any;
      
          dragulaService.drag.subscribe((value) => {
            let id = Number(value[1].dataset.id);
            let orgId: Number = value[0].split('-')[1];
            elementNode = value[2].querySelectorAll('.contact:not(.ignore)').item(dragIndex);
      
            if (!!id) {
              // this renderedOrgs is just an array to hold the org options that render in this particular view
              this._organizationService.renderedOrgs.push(this.org);
              this.thisOrg = this._organizationService.renderedOrgs.filter(org => { return org.id == orgId; })[0];
              this.thisContact = this.thisOrg.contacts.filter(contact => { return contact.id == id; })[0];
      
              let arr = this.thisOrg.contacts.map(x => { return x.id; });
              dragIndex = arr.indexOf(id);
            }
          });
      
          dragulaService.drop.subscribe((value: any[]) => {
            if (elementNode) {
                let id = Number(elementNode.dataset.id);
                if (!!id) {
                  let arr = this.thisOrg.contacts.map(x => { return x.id; });
                  dropIndex = arr.indexOf(id);
                }
            }
      
            if (value[2] === value[3]) { // target container === source container
                if (dragIndex >= 0 && dropIndex >= 0 && dragIndex !== dropIndex) {
                  this.thisOrg.contacts.forEach((contact, index) => {
                    contact.sequence = index;
                    this.updateSequence(contact.id, index);
                  });
                }
            }
          });
        }
      
        updateSequence (id: Number, index: Number) {
          let contactBody = {
            avatar: {
              sequence: index,
            }
          };
      
          return this._contactService.contactsIdPut(id, contactBody)
            .subscribe(
              (data: any) => {
                // nothing is needed, the same view can apply because the contact has already been moved.
              },
              (error: any) => {
                console.error(error);
              }
            );
        }
      }
      

      希望这可以让其他人更清楚地了解这个问题,就像我今天发现自己的地方一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-09-22
        • 2016-08-23
        • 1970-01-01
        • 2017-02-25
        • 1970-01-01
        • 2016-10-15
        • 2016-06-11
        • 2016-12-04
        相关资源
        最近更新 更多