Sebmaster / racer-example

an example on how to connect racer.js and angular.js
19 stars 5 forks source link

racer init magic :O #3

Closed kristianmandrup closed 10 years ago

kristianmandrup commented 10 years ago

Hi Sebastian,

I'm still trying to wrap my head around your magic code. This part is still very much magic to me!

app.get('/model', function (req, res) {
        var model = store.createModel();
        model.subscribe('entries', function (err, entries) {
                if (err) {
                        res.status(500);
                        res.send(err);
                } else {
                        model.bundle(function (err, bundle) {
                                res.send(JSON.stringify(bundle));
                        });
                }
        });
});

// huh!?
store.bundle(__dirname + '/client.js', function (err, js) {
        app.get('/script.js', function (req, res) {
                res.type('js');
                res.send(js);
        });
});

And on the client you init racer using:

                $http.get('/model').success(function (data) {
                        racer.init(data);
                });

How does this all work? Especially the last part: store.bundle is very cryptic! Looks like you are sending a complete script.js file back to the client. Does this file contain the whole racer model as json, which is then evaluated on the client and stored as the local racer model on first connect? Wauw!

I would like to achieve the same kind of magic using socket.io. Could you help me achieve this perhaps? Thanks :)

Sebmaster commented 10 years ago

The store bundle is needed for the racer js script. It produces a single script which contains all racer dependencies and the angular service. It's just loaded by a script in the final page, so I wouldn't worry about it.

You might be able to transfer the model data through socket.io if you think that's really necessary. It's basically a snapshot of the current model state, which is used to initialize racer.

If you're not using any socket.io routing libs I think it's just a matter of emit()ting the same model bundle with socket.io instead of transfering it via http and then on() on the client and call racer.init with that same data.

kristianmandrup commented 10 years ago

Ah, so the script.js is connected like this and just used to load the necessary client side racer javascript?

        app.get('/script.js', function (req, res) {
                res.type('js');
                res.send(js);
        });

<script src="/script.js"></script>

but why is it wrapped in the following?

store.bundle(__dirname + '/client.js', function (err, js) {

I don't see where this fits in, except if it is connected here:

else {
                        model.bundle(function (err, bundle) {
                                res.send(JSON.stringify(bundle));
                        });
                }

So I guess, what you mean is that I could just do a socket.emit('data', JSON.stringify(bundle)); instead of the res.send ? thanks!

Sebmaster commented 10 years ago

but why is it wrapped in the following?

That function generates the resulting script text with browserify and I think it also minifies it in production if I remember correctly.

So I guess, what you mean is that I could just do a socket.emit('data', JSON.stringify(bundle)); instead of the res.send ? Yes.

kristianmandrup commented 10 years ago

What I also don't get it this part:

// function to send back a bundle of the updated data
var racerDataBundler = function (err) {
    if (err) {
        io.emit('error', err);
    } else {
        model.bundle(function (err, bundle) {
            io.emit('data', JSON.stringify(bundle));
        });
    }
}

io.sockets.on('connection', function (socket) {
    for (model in models) {
        storedModel.subscribe(model, racerDataBundler);
    }
});

would I really have to subscribe to each model or only to the global racer model? your example is not very clear on this part as you mix 'entries' in here...

So I thought I should do something like this...

var models = ['todos', 'users'];

var storedModel = store.createModel();

app.get('/model', function (req, res) {
    // subscribe on updates to each model
    for (model in models) {
        storedModel.subscribe(model, racerDataBundler);        
    }
});

but with my latest understanding, you bundle the entire model and subscribe only to the global model? So this is the way to go...

var storedModel = store.createModel();

app.get('/model', function (req, res) {
    // subscribe to any (mutation) event on global racer model
    storedModel.subscribe('racer-model', racerDataBundler);        
});

// or using sockets

io.sockets.on('connection', function (socket) {
    // subscribe to any (mutation) event on global racer model
    storedModel.subscribe('racer-model', racerDataBundler);        
});

Cool :) I'm finally starting to make sense of it.

Sebmaster commented 10 years ago

but with my latest understanding, you bundle the entire model and subscribe only to the global model?

I made it a bit easy for me, because the todo example only has a single mongo collection and therefore only a single model to subscribe to. If you want to subscribe to all models, you'd have to call subscribe for all of them and bundle the model after all of the subscribes have finished. However, depending on the amount of your data that might get a bit excessive so be careful there.

kristianmandrup commented 10 years ago

So awesome!!!! Thanks :)