2

Been looking to figure out how with Twitter Flight can attach to dynamic created elements.

Having the following HTML

<article>Add element</article>

And the following component definition

var Article = flight.component(function () {
    this.addElement = function () {
        this.$node.parent().append('<article>Add element</article>');
    };

    this.after('initialize', function () {
        this.on('click', this.addElement);
    });
});
Article.attachTo('article');

Once a new element is created, the click event doesn't fire. Here's the fiddle: http://jsfiddle.net/smxx5/

Johann
  • 137
  • 1
  • 9

3 Answers3

3

That's not how you should be using Flight imho.

Each component should be isolated from the rest of the application, therefore you should avoid this.$node.parent()

On the other hand you can interact with descendants.

My suggestion is to create an "Articles manager" component that uses event delegation. eg.

http://jsfiddle.net/kd75v/

<div class="js-articles">
    <article class="js-article-add">Add element</article>
<div/>

and

var ArticlesManager = flight.component(function () {

    this.defaultAttrs({
        addSelector: '.js-article-add',
        articleTpl: '<article class="js-article-add">Add element</article>'
    });

    this.addArticle = function () {
        this.$node.append(this.attr.articleTpl);
    };

    this.after('initialize', function () {
        this.on('click', {
            addSelector: this.addArticle
        });
    });
});

ArticlesManager.attachTo('.js-articles');
G.G.
  • 634
  • 1
  • 5
  • 10
  • This is totaly correct, but how do you handle this is you want to add an element like the ArticlesManager? For example you want to ajaxify your page and change the complete body of the page? – MarvinK Jan 05 '15 at 14:48
  • @MarvinK you'd need a bootloader like http://git.io/DvDy6w - this is for a full page rendering, in the ajaxified case you'd get `flight_initialize` and `flight_settings` from the server. You can also attach the `ArticlesManager` to the `document` element or `document.body` and it'll work thanks to the event delegation: `this.on('click', { addSelector: this.addArticle });` – G.G. Jan 24 '15 at 06:08
1

Try attaching Article to each new article added:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/smxx5/2/

var Article = flight.component(function () {
    this.addElement = function () {
        var newArticle = $('<article>Add element</article>');
        this.$node.parent().append(newArticle);
        Article.attachTo(newArticle);
    };

    this.after('initialize', function () {
        this.on('click', this.addElement);
    });
});

Article.attachTo('article');

The Article.attachTo('article'); at the end, that runs once on load, will only attach to existing article elements.

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
0

I hit this problem, and worked around is as follows...

Javascript: All thrown together for brevity, but could easily be separated.

(function(){
    var TestComponent, LoaderComponent;

    TestComponent = flight.component(function() {
        this.doSomething = function()
        {
            console.log('hi there...');
        };

        this.after('initialize', function() {
            this.on('mouseover', this.doSomething);
        });
    });

    LoaderComponent = flight.component(function() {
        this.attachComponents = function()
        {
            TestComponent.attachTo('.test');
        };

        this.after('initialize', function() {
            // Initalise existing components
            this.attachComponents();

            // New item created, so re-attach components
            this.on('newItem:testComponent', this.attachComponents);
        });        
    });

    LoaderComponent.attachTo('body');
}());

HTML: Note that one .test node exists. This will be picked up by Flight on initialization (i.e. not dynamic). We then add a second .test node using jQuery and fire off the event that the LoaderComponent is listening on.

<div class="test">
    <p>Some sample text.</p>
</div>

<script>
$('body').append('<div class="test"><p>Some other text</p></div>').trigger('newItem:testComponent');
</script>

This is obviously a very contrived example, but should show that it's possible to use Flight with dynamically created elements.

Hope that helped :)

Tom Seldon
  • 510
  • 1
  • 6
  • 10