2016-07-14 8 views
1

Ich bin ein Drag-und-Drop-Arbeitsbereich, ähnlich denen, die Sie für die Herstellung von Mockups finden. Ich habe ein benutzerdefiniertes Arbeitsbereichselement mit einem größeren verschachtelten Element, das gezoomt und geschwenkt werden kann. Daher muss ich die Größe und die Positionsdaten des Arbeitsbereichs und aller darin enthaltenen Elemente sorgfältig verfolgen.Auslöser Callback nach Bindungen in Aurelia neu bewerten

In meinem fügtes Ereignisse meines benutzerdefinierten Elements, habe ich programmatisch die Höhe und Breite des Arbeitsbereiches als JavaScript-Objekt, das die CSS in der Ansicht gebunden ist:

workspaceCustomElement.js

export class WorkspaceCustomElement { 

    constructor(element) { 
     this.element = element; 
    } 

    attached() { 
     this.workspace.size = { 
      height: this.element.height * 5, 
      width: this.element.width * 5 
     } 
    } 
} 

workspaceCustomElement.html

<div css="height: ${workspace.height}px; width: ${workspace.width}px; 
    left: ${(element.clientWidth - workspace.width)/2}px; 
    top: ${(element.clientHeight - workspace.height)/2}px;"></div> 

Jetzt habe ich Probleme, die Positionen meiner Kindelemente zu erfassen. Ich habe auch Callbacks an sie angehängt, aber sie werden vor der angefügte Rückruf oben bewertet, und so die CSS-Bindung wurde nicht ausgewertet, und die Größe und Positionen sind falsch.

Ich brauche einen Rückruf hinzufügen nach der attached() wurde ausgewertet und die Bindungen wurden aktualisiert. Ich kann dies erreichen, indem Sie einen setTimeout Hack verwenden, aber ich habe kein Vertrauen, dass dies immer funktioniert.

attached() { 
    this.workspace.size = { 
     height: this.element.height * 5, 
     width: this.element.width * 5 
    } 

    setTimeout(() => { 
     let components = this.element.querySelectorAll('.component'); 
     Array.prototype.forEach.call(components, (component) => { 
      let model = component.model; 
      model.position = { 
       x: component.clientLeft, 
       y: component.clientTop 
      }; 
     } 
    }, 0) 
} 

Gibt es eine bessere, zuverlässigere Möglichkeit, eine Anweisung nach dem nächsten verbindlichen Update in die Warteschlange zu stellen?

+2

Wie wäre es mit Aurelias 'TaskQueue'? http://stackoverflow.com/questions/36049391/is-there-a-callback-or-promise-for-aurelia-show-bind –

Antwort

4

Die beste Vorgehensweise besteht darin, dem TaskQueue eine Aufgabe hinzuzufügen. Unter der Haube verwendet die Bindungsmaschine die TaskQueue selbst, also fügt das Hinzufügen einer neuen Aufgabe sie hinter den Bindungsaktualisierungen in die Warteschlange ein.

workspaceCustomElement.js

export class WorkspaceCustomElement { 

    constructor(element, queue) { 
     this.element = element; 
     this.queue = queue; 
    } 

    attached() { 
     this.workspace.size = { 
      height: this.element.height * 5, 
      width: this.element.width * 5 
     } 
     this.queue.queueMicroTask(() => { 
      let components = this.element.querySelectorAll('.component'); 
      Array.prototype.forEach.call(components, (component) => { 
       let model = component.model; 
       model.position = { 
        x: component.clientLeft, 
        y: component.clientTop 
       }; 
      } 
     }); 
    } 
} 

Sehen Sie hier für weitere Informationen: TaskQueue API

3

Sie ein verbindliches Verhalten erstellen können, die einen Rückruf Ihrer Wahl aufruft, wenn die Bindungsaktualisierungen das Ziel (das DOM-Element/benutzerdefiniertes Element/benutzerdefiniertes Attribut).

Hier ist ein Beispiel: https://gist.run?id=28c0fedb21b5d8100913d3bc5500499f

ziel updated.js

export class TargetUpdatedBindingBehavior { 
    bind(binding, source, callback) { 
    // override the binding's updateTarget method. add logic to invoke 
    // the callback passed as a parameter to the binding behavior. 
    binding.standardUpdateTarget = binding.updateTarget; 
    binding.targetUpdatedCallback = callback; 
    binding.updateTarget = function(value) { 
     this.standardUpdateTarget(value); 
     this.targetUpdatedCallback(this.target, this.targetProperty, value); 
    }; 
    } 

    unbind(binding, source) { 
    // revert the binding to it's original state. 
    binding.updateTarget = binding.standardUpdateTarget; 
    binding.standardUpdateTarget = null; 
    binding.targetUpdatedCallback = null; 
    } 
} 

http://aurelia.io/hub.html#/doc/article/aurelia/binding/latest/binding-binding-behaviors

@ MathewJamesDavis Antwort perfekt gültig ist, ich biete dies nur als zweite Wahl.

+0

Wow cool, in meinem Fall wäre dies nicht eine knifflige Umsetzung, da ich ' m Auslöser für ein Array von Elementen? –

+0

Das ist genial, ich benutze diese Technik an vielen Orten.Grundsätzlich überall, wenn ich keine direkte Bindung will, nur ausgelöst, wenn sich etwas geändert hat. – balazska