Questions about Controller and Class in JavaScriptMVC framework - javascriptmvc

$.Controller("Whiteboard", {}, {
init: function(){
var pen = new Pen();
},
sendRequest: function() {
// This function should listen draw/erasing events from Pen
}
});
$.Class("Pen",{},{
init: function() {
// Pen setup, click to draw etc..
}
});
Something like this, I want the Whiteboard listen events from Pen, how can I do this? I need Controller listen on a Class.

If this is JMVC 3.2+ you can do something like this:
$('.whiteboard').whiteboard({pen:new Pen()});
$.Controller("Whiteboard", {}, {
"{pen} draw": function() {
this.sendRequest();
}
});
$.Observe('Pen',{},{
draw: function() {
$(this).triggerHandler('draw');
}
});
For JMVC 3.1, you'll have to use $.Model instead of $.Observe and use this.bind in your controller like this:
$.Controller("Whiteboard", {}, {
init: function() {
this.bind(this.options.pen,'draw',this.callback('sendRequest'));
}
});

Related

React and Socket.io: Able to get initial data - but view doesn't update when a new post comes in

Not sure if the issue is how I have my sockets setup - or if I am incorrectly trying to render the data with React.
I can successfully pull in data with my socket - yet it doesn't live update state when new data is posted to the server. My intention is for the state in React to automatically render new data, which is always live because of the socket connection.
Here is my client app that gets messages from the server and renders them:
var Chat = React.createClass({
getInitialState: function() {
return {
messages: null
}
},
componentWillMount: function(){
var self = this;
socket.emit('getMessages');
socket.on('serverMessages', function (data) {
self.setState({messages: data})
});
},
render: function() {
var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null
return (
<div className="jumbotron">
{ messages }
<MessageForm submitMessage={this.submitMessage}/>
</div>
);
}
});
Just in case here is my server code that emits data:
io.on('connection', function (socket) {
socket.on('getMessages', function (data) {
Message.find(function(err, messages){
socket.emit('serverMessages', messages);
})
});
});
As of right now, you're "just" grabbing data from the server once the component has been loaded. To get something a bit more "real time" you'll want to either ping the server with the same emit statement you specified regularly (which defeats the point of using websockets, really, you could use long-polling) or have the server regularly send new data to all clients.
You can do EITHER:
A) Client side: "Polling" for information [Not Ideal]
Note: I initially put this in my answer because I saw the OP was "polling" when the controller was loaded. I didn't click on that this might be because the controller may not be loaded with the websocket so sending data on connect might not work here. My bad.
Replace socket.emit('getMessages') with something that will "poll" the websocket regularly for data:
setInterval(function () {
socket.emit('getMessages')
}, 10000); /* Request data from the socket every 10 seconds */
OR
B) Server side: Send new data as it becomes available. [Best Way]
Track all clients via a clients array and delete them from it when their session ends.
var clients = [];
io.on('connection', function (socket) {
clients.push(socket);
socket.on('end', function () {
// Could also splice the array below, but it still works.
delete clients[clients.indexOf(socket)];
});
/* Previous logic for server goes here */
});
Run this code when you need to push new messages from the database/data storage:
for (var i in clients) {
clients[i].emit('serverMessages', /* messages object */);
}
Your server code is only firing upon initial socket connection.
Server:
socket.on('getMessages', function (data) {
Message.find(function(err, messages){
socket.emit('serverMessages', messages);
})
});
Client:
var Chat = React.createClass({
getInitialState: function() {
return {
messages: null
}
},
componentWillMount: function(){
var self = this;
socket.emit('getMessages');
socket.on('serverMessages', function (data) {
self.setState({messages: data})
});
},
render: function() {
var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null
return (
<div className="jumbotron">
{ messages }
</div>
);
}
});
Based on naming convention, it also appears that your Message.find() is pulling a single message. I would recommend clarifying the labeling to match cardinality.
Try this:
var Chat = React.createClass({
getInitialState: function() {
return {
messages: null
}
},
componentWillMount: function(){
var self = this;
socket.emit('getMessages');
socket.on('serverMessages', function (data) {
self.setState({messages: data})
});
},
render: function() {
var messages = this.state.messages ? <MessageList messages={this.state.messages}/> : null
return (
<div className="jumbotron">
{ messages }
<MessageForm submitMessage={this.submitMessage}/>
</div>
);
}
});
Could it be possible its due to the componentWillMount lifecycle method? Could you try the componentDidMount instead.
It looks like render will see the state update but only gets executed once despite the state change according to facebook.

Flux eventemitter

I am currently trying out the FLUX design pattern and I have stumpled upon an issue. In this project I am also using ReactJS to go with it. It is working fine to a point where it is almost done, but screws up. So I am starting the function(s) with a button that I render, when clicked it fires the chain of functions.
render: function(){
return (
<div><button onClick={this.waiting}>Hello</button>
{this.state.results}
</div>
)
}
you can now see that when this button is clicked, it fires a function called waiting() which contains the following
waiting: function() {
actions.trending();
return this.state.results;
},
So it fires the function and the following happens
var actions = {
trending: function(){
api.trending()
.then(function(result){
dispatcher.dispatch({
actionType: actionConstants.TRENDING_RESULT,
results: result
});
}, function(error){
console.log(error);
dispatcher.dispatch({
actionType: actionConstants.ERROR,
error: error
});
});
}
};
which is all working fine, I am getting my data and I am happy so far, problem is what happens next, when the dispatcher dispatches the actionType along with the data, this goes into the store I have. In my store-file I am then registering the payload(action).
dispatcher.register(function(action){
switch (action.actionType) {
case actionConstants.TRENDING_RESULT:
console.log(action.results); <- I can actually see my data
results = action.results;
resultErrors = null;
SearchStore.emit(actionConstants.TRENDING_RESULT); <- Error
break;
case actionConstants.ERROR:
results = null;
resultErrors = action.error;
console.log(resultErrors);
SearchStore.emit(actionsConstants.ERROR);
break;
}
});
So at this point I can see my data in the console.log but I am getting an error at the emit function that sounds as following
Uncaught (in promise) TypeError: this._events[evt].push
for my store functions I use the following
var SearchStore = {
getTrending: function() {
return JSON.stringify(results);
},
getError: function() {
return resultErrors;
},
emit: function(event) {
eventEmitter.on(event);
},
on: function(event, callback) {
eventEmitter.on(event, callback);
},
removeListener: function(event, callback) {
eventEmitter.removeListener(event, callback);
}
};
and finally to pick up on any emits I call my on function in ComponentDidMount that looks like this
componentDidMount: function(){
SearchStore.on(actionConstants.TRENDING_RESULT, this.loadResults());
SearchStore.on(actionConstants.ERROR, this.showError());
},
componentWillUnmount: function(){
SearchStore.removeListener(actionConstants.TRENDING_RESULT, this.loadResults());
SearchStore.removeListener(actionConstants.ERROR, this.showError());
},
For the Dispatcher I am using Facebooks FLUX dispatcher and for the emitter I am using eventemitter3. Everything is going smoothly up until I try to emit TRENDING_RESULT and and the payload with it. I am terribly sorry about the length of this question, but I wanted to be as thorough as I possibly could for your understanding.
The event emitter should call emit function not the on function.
So it should be something like:
var SearchStore = {
getTrending: function() {
return JSON.stringify(results);
},
getError: function() {
return resultErrors;
},
emit: function(event) {
eventEmitter.emit(event); // HERE!!
},
on: function(event, callback) {
eventEmitter.on(event, callback);
},
removeListener: function(event, callback) {
eventEmitter.removeListener(event, callback);
}
};
My solution was as following:
'use strict';
var dispatcher = require('../dispatcher/dispatcher');
var EventEmitter = require('events').EventEmitter;
var ObjectAssign = require('object-assign');
var actionConstants = require('../constants/actionConstants');
var _store = {
list: [],
error: [],
genres: [],
playlists: []
}
var resultErrors = null;
var CHANGE_EVENT = 'change';
var SearchStore = ObjectAssign( {}, EventEmitter.prototype, {
getTrending: function() {
return _store;
},
getError: function() {
return _store;
},
addChangeListener: function(callback){
this.on(CHANGE_EVENT, callback);
},
removeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
getGenres: function() {
return _store;
},
getPlaylists: function() {
return _store;
}
});
dispatcher.register(function(action){
switch (action.actionType) {
case actionConstants.TRENDING_RESULT:
action.results.map(function(item){
_store.list.push(item);
});
resultErrors = null;
SearchStore.emit(CHANGE_EVENT);
break;
case actionConstants.SEARCH_RESULT:
_store.list = [];
console.log(_store.list);
action.results.map(function(item){
_store.list.push(item);
});
resultErrors = null;
SearchStore.emit(CHANGE_EVENT);
break;
case actionConstants.ERROR:
results = null;
_store.error.push(action.error);
SearchStore.emit(CHANGE_EVENT);
break;
case actionConstants.ADD_GENRE:
_store.genres.push(action.index);
SearchStore.emit(CHANGE_EVENT);
break;
case actionConstants.REMOVE_GENRE:
_store.genres = _store.genres.filter(function(index){
return index !== action.index;
});
console.log(_store.genres);
SearchStore.emit(CHANGE_EVENT);
break;
case actionConstants.SAVE_PLAYLIST:
var playlists = {
"name": action.index,
"items": {}
}
;
_store.playlists.push(playlists);
SearchStore.emit(CHANGE_EVENT);
break;
default:
}
});
So I eliminated my my "emit" and "on" function all together and made a addChangeListener. so I emit straight from my switch cases and since "emit" is a already a function I don't need to create a function for a "emit" function. I just use my listener to pick up on CHANGE_EVENT and then it will run a callback function. Example:
componentDidMount: function(){
SearchStore.addChangeListener(this.loadPlaylists);
},
componentWillUnmount: function(){
SearchStore.removeListener(this.loadPlaylists);
},
As it is now it works perfectly, I understand that if I had just looked thoroughly through my code I could have been saved the trouble but the more you learn right? Anyways thanks for your time yet again.

How to use Knockout Mapping plugin in Hottowel

i was able to install ko.mapping in VisualStudio but when i try to map some Json Data in my view it does not work. can anyone tell me what i am doing wrong ?
here is my viewmodel
define(['plugins/router', 'knockout', 'services/logger', 'durandal/app', 'mapping'], function (router, ko, logger, app, mapping) {
//#region Internal Methods
function activate() {
logger.log('Google Books View Activated', null, 'books', true);
return true;
}
//#endregion
//==jquery=================================================
function attached() {
}//-->end of viewAttached()
//========VIEWMODEL========================================
var ViewModel = function (data) {
activate = activate;
attached = attached;
title = 'google Books';
};
return new ViewModel();
});
and here ist an working example in Jsfiddle
I don't think that you don't need to return a new View Model. you just need to return the view model.
define(['plugins/router', 'knockout', 'services/logger', 'durandal/app', 'mapping'],
function (router, ko, logger, app, mapping) {
var books = ko.observableArray();
function activate() {
getBooks().then(function(){
logger.log('Google Books View Activated', null, 'books', true);
return true;
});
}
function attached() {
}
function getBooks(){
$.getJSON(url, function (data) {
vm.books(ko.mapping.fromJS(data));
return true;
});
}
var vm = {
activate : activate,
attached : attached,
title : 'google Books',
books: books
};
return vm;
});
EDIT
To find requirejs errors add to your main.js file. It should help in tracking down requirejs module loading errors.
requirejs.onError = function (err) {
console.log(err.requireType);
if (err.requireType === 'timeout') {
console.log('modules: ' + err.requireModules);
}
throw err;
};

Nodeunit testing for serial communication

I'm writing an npm module to interface with a piLite with node.js. I'd like to write it properly using TDD principles.
The code I need to test:
var SerialPort = require("serialport").SerialPort;
exports.PiLite = {
device: "/dev/ttyAMA0",
baudrate: 9600,
client: null,
init: function() {
this.client = new SerialPort(this.device, {
baudrate: this.baudrate
}, false);
},
connect: function(callback) {
this.init();
this.client.open(function() {
console.log('Connected to Pi Lite');
callback();
});
},
write: function (data) {
...
The standard usage would be:
var pilite = require('pilite').PiLite;
pilite.connect(function() {
pilite.write('some data');
// calls to functions to send messages to pilite
}
I understand how to test assertions but I don't see how I can test the connectivity to the serial port.
Should I test for it or just test the functions I'm using to write to the serial port?
Edit: I'm pretty new to Nodeunit so any pointers in the right direction would be great.

how to solve 'this' problems with node libraries like async and request

I've written a node script that gets some data by requesting REST API data (using the library request). It consists of a couple of functions like so:
var data = { /* object to store all data */ },
function getKloutData() {
request(url, function() { /* store data */}
}
// and a function for twitter data
Because I want to do some stuff after fetching all the I used the library async to run all the fetch functions like so:
async.parallel([ getTwitterData, getKloutData ], function() {
console.log('done');
});
This all works fine, however I wanted to put everything inside a object pattern so I could fetch multiple accounts at the same time:
function Fetcher(name) {
this.userID = ''
this.user = { /* data */ }
this.init();
}
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
request(url, function () { /* store data */ });
};
This doesn't work because async and request change the this context. The only way I could get around it is by binding everything I pass through async and request:
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData.bind(this), this.getKloutData.bind(this) ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
function saveData() {
/* store data */
}
request(url, saveData.bind(this);
};
Am I doing something basic wrong or something? I think reverting to the script and forking it to child_processes creates to much overhead.
You're doing it exactly right.
The alternative is to keep a reference to the object always in context instead of using bind, but that requires some gymnastics:
Fetcher.prototype.init = function() {
var self = this;
async.parallel([
function(){ return self.getTwitterData() },
function(){ return self.getKloutData() }
], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
var self = this;
function saveData() {
// store data
self.blah();
}
request(url, saveData);
};
You can also do the binding beforehand:
Fetcher.prototype.bindAll = function(){
this.getKloutData = this.prototype.getKloutData.bind(this);
this.getTwitterData = this.prototype.getTwitterData.bind(this);
};
Fetcher.prototype.init = function(){
this.bindAll();
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
};
You can save this into another variable:
var me = this;
Then me is your this.
Instantiate object with this function:
function newClass(klass) {
var obj = new klass;
$.map(obj, function(value, key) {
if (typeof value == "function") {
obj[key] = value.bind(obj);
}
});
return obj;
}
This will do automatic binding of all function, so you will get object in habitual OOP style,
when methods inside objects has context of its object.
So you instantiate you objects not through the:
var obj = new Fetcher();
But:
var obj = newClass(Fetcher);

Resources