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.
Related
I'm trying to prevent the user to save a piece if it doesn't achieve some requirements.
Currently I'm doing it like this:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
let error = "";
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
self.apos.notify(req, "Check the compatibility between parent event and subevents", { type: "error" });
error = "Subevents are not compatible with parent event";
}
callback(error);
};
This works but the problem is it shows 2 errors notifications (the default and my custom), 1 because of callback(error) and 1 because of apos.notify.
Any idea how to stop the item of being saved and only show my notification?
Thanks in advance.
UPDATE 1:
As Tom pointed out, my code looks like this now:
// lib/modules/events/public/js/editor-modal.js
apos.define('events-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
apos.notify('A message suitable for this case.', { type: 'error' });
} else {
apos.notify('A generic error message.', { type: 'error' });
}
};
}
});
// lib/modules/events/index.js
var superPushAssets = self.pushAssets;
self.pushAssets = function() {
superPushAssets();
self.pushAsset("script", "editor-modal", { when: "user" });
};
self.beforeSave = async function(req, piece, options, callback) {
return callback("incompatible")
};
For testing purposes I'm just returning the error in beforeSave. The problem is that an exception is being thrown in the browser console and the modal is not properly rendered again. Here's a screenshot about what I'm talking:
I'm trying to debug it and understand what's happening but no clue yet.
In your server-side code:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
return callback('incompatible');
}
return callback(null);
};
And on the browser side:
// in lib/modules/my-pieces-module/public/js/editor-modal.js
apos.define('my-pieces-module-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
return 'A message suitable for this case.';
} else {
return 'A generic error message.';
}
};
}
});
If the error reported by the callback is a string, it is passed to the browser. The browser can then recognize that case and handle it specially. 'my-pieces-module-editor-modal' should be substituted with the name of your pieces module followed by -editor-modal.
I am trying to ask a question to the user and using AMAZON.yesIntent and noIntent to capture the response. In case I get response, I am calling other function which should emit something back to user. But the emit is not being called. Code below:
'use strict';
var Alexa = require("alexa-sdk");
var https = require('https');
var alexa;
exports.handler = function(event, context, callback) {
alexa = Alexa.handler(event, context);
alexa.registerHandlers(handlers);
alexa.execute();
};
var handlers = {
'LaunchRequest': function() {
alexa.emit(':ask', 'my text');
},
'oneShotIntent': function() {
var self = this;
// removed the code for simplicity
self.attributes['yes_no'] = true;
alexa.emit(':ask', 'sample yes no question');
})
},
'AMAZON.YesIntent': function () {
if (this.attributes['yes_no']) {
delete this.attributes['yes_no'];
alexa.emit('oneShotSecond');
}
},
'oneShotSecond': function() {
delete this.attributes['yes_no']; // already deleted
// removed code for simplicity
var self = this;
// removed code for simplicity
console.log(info);
if (info) {
console.log('here in if condition');
self.emit(':tell', 'sample text');
} else {
self.emit(':tell', 'sorry failed');
}
});
}
};
The first emit is working. The console.log in other function are happening. But emit is failing.
No logs in cloudwatch also. It just ends after printing the console.log data points.
Any help?
I am not sure if I understand
alexa.emit('oneShotSecond');
However I would have done it like below
oneShotSecond(this);
And then
'oneShotSecond': function(self) { // use self.emit}
I created a function to:
take an array of 'labels' and look for whether they have a record in the db already
create those which don't exist,
and update those which do exist
return a json array reporting on each item, whether they were updated/created, or resulted in an error
I managed to make it work but I feel like I just made some ugly dogs' dinner!
var models = require("../models");
var Promise = models.Sequelize.Promise;
module.exports = {
addBeans: function (req, callback) {
Promise.map(req.body.beansArr, function (bean) {
return models.Portfolio.findOrCreate({where: {label: bean}}, {label: bean});
}).then(function (results) { // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
var promisesArr = [];
results.forEach(function (result) {
if (result[1]) { // result[1] = wasCreated
promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));
} else {
promisesArr.push(
models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).then(function () {
return Promise.resolve([result[0].dataValues.label, "updated"])
})
);
}
});
return promisesArr;
// When it's all done create a JSON response
}).then(function (results) {
var resultObj = {items: []}; // JSON to return at the end
Promise.settle(results).then(function (promiseinstances) {
for (var i = 0; i < promiseInstances.length; i++) {
if (promiseInstances[i].isFulfilled()) {
resultObj.items.push({
item: {
label: promiseInstances[i].value()[0],
result: promiseInstances[i].value()[1],
error: ''
}
});
}
else if (promiseInstances[i].isRejected()){
resultObj.items.push({
label: promiseInstances[i].value()[0],
result: 'error',
error: promiseInstances[i].reason()
});
}
}
// Send the response back to caller
}).then(function () {
return callback(null, resultObj);
}, function (e) {
return callback(e, resultObj);
});
});
}
};
Question:
Is there an easier or more obvious way to create/update values with Sequelize?
Is my use of Promise.settle() appropriate for this case? I have the feeling I made this more complicated than it needs to be.
I am new to Sequelize and using Promises, I'd appreciate if someone could advise on this.
I feel like this would work better on CodeReview.SE but I can see a few issues.
Is there an easier or more obvious way to create/update values with Sequelize?
Well, for one thing:
.then(function(array){
var newArr = [];
array.forEach(function(elem){
newArr.push(fn(elem);
}
return newArr;
});
Is just
.map(fn)
Additionally, promises assimilate so you can return val; from a .then you don't have to return Promise.resolve(val);.
So:
).then(function (results) { // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
var promisesArr = [];
results.forEach(function (result) {
if (result[1]) { // result[1] = wasCreated
promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));
} else {
promisesArr.push(
models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).then(function () {
return Promise.resolve([result[0].dataValues.label, "updated"])
})
);
}
});
return promisesArr;
})
Is just
.map(function(result){
if(result[1]) return [result[0].dataValues.label, "created"];
return models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).
return([result[0].dataValues.label, "updated"]);
});
However, since you want it to work regardless of it being resolved, you'd have to do:
.then(function(results){
return results.map(function(result){
if(result[1]) return [result[0].dataValues.label, "created"];
return models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).
return([result[0].dataValues.label, "updated"]);
});
});
Which means it'll resolve regardless, then you'd call .settle():
.settle().then(function(results){
// your settle logic here
});
Note that the last:
}).then(function () {
return callback(null, resultObj);
}, function (e) {
return callback(e, resultObj);
});
Is simply:
.nodeify(callback);
However, I recommend sticking to promises.
I use Promise.settle for sequelize.update, and can get affect rows number by _settledValueField .
promise.push(...update...)
db.sequelize.Promise.settle(promise).then(function (allresult) {
var affectcnt = 0
allresult.forEach(function (singlecnt) {
if (undefined !== singlecnt._settledValueField[1]) {
affectcnt += parseInt(singlecnt._settledValueField[1])
}
})
unfortunately, it's only work for update.
You can insert array in database using sequelize. You want to change in model like below. I am trying to add multiple languages in database through array.
language: { type: DataTypes.STRING,
allowNull: false,
get()
{
return this.getDataValue('language').split(';')
},
set(val)
{
this.setDataValue('language',Array.isArray(val) ? val.join(','):val);
}
}
I'm trying to convert an existing API to work with RxJS... fairly new to node, and very new to RxJs, so please bear with me.
I have an existing API (getNextMessage), that either blocks (asynchronously), or returns a new item or error via a node-style (err, val) callback, when the something becomes available.
so it looks something like:
getNextMessage(nodeStyleCompletionCallback);
You could think of getNextMessage like an http request, that completes in the future, when the server responds, but you do need to call getNextMessage again, once a message is received, to keep getting new items from the server.
So, in order to make it into an observable collection, I have to get RxJs to keep calling my getNextMessage function until the subscriber is disposed();
Basically, I'm trying to create my own RxJs observable collection.
The problems are:
I don't know how to make subscriber.dispose() kill the async.forever
I probably shouldn't be using async.forever in the first place
I'm not sure I should be even getting 'completed' for each message - shouldn't that be at the end of a sequence
I'd like to eventually remove the need for using fromNodeCallback, to have a first class RxJS observable
Clearly I'm a little confused.
Would love a bit of help, thanks!
Here is my existing code:
var Rx = require('rx');
var port = require('../lib/port');
var async = require('async');
function observableReceive(portName)
{
var observerCallback;
var listenPort = new port(portName);
var disposed = false;
var asyncReceive = function(asyncCallback)
{
listenPort.getNextMessage(
function(error, json)
{
observerCallback(error, json);
if (!disposed)
setImmediate(asyncCallback);
}
);
}
return function(outerCallback)
{
observerCallback = outerCallback;
async.forever(asyncReceive);
}
}
var receive = Rx.Observable.fromNodeCallback(observableReceive('rxtest'));
var source = receive();
var subscription = source.forEach(
function (json)
{
console.log('receive completed: ' + JSON.stringify(json));
},
function (error) {
console.log("receive failed: " + error.toString());
},
function () {
console.log('Completed');
subscription.dispose();
}
);
So here's probably what I would do.
var Rx = require('Rx');
// This is just for kicks. You have your own getNextMessage to use. ;)
var getNextMessage = (function(){
var i = 1;
return function (callback) {
setTimeout(function () {
if (i > 10) {
callback("lawdy lawd it's ova' ten, ya'll.");
} else {
callback(undefined, i++);
}
}, 5);
};
}());
// This just makes an observable version of getNextMessage.
var nextMessageAsObservable = Rx.Observable.create(function (o) {
getNextMessage(function (err, val) {
if (err) {
o.onError(err);
} else {
o.onNext(val);
o.onCompleted();
}
});
});
// This repeats the call to getNextMessage as many times (11) as you want.
// "take" will cancel the subscription after receiving 11 items.
nextMessageAsObservable
.repeat()
.take(11)
.subscribe(
function (x) { console.log('next', x); },
function (err) { console.log('error', err); },
function () { console.log('done'); }
);
I realize this is over a year old, but I think a better solution for this would be to make use of recursive scheduling instead:
Rx.Observable.forever = function(next, scheduler) {
scheduler = scheduler || Rx.Scheduler.default,
//Internally wrap the the callback into an observable
next = Rx.Observable.fromNodeCallback(next);
return Rx.Observable.create(function(observer) {
var disposable = new Rx.SingleAssignmentDisposable(),
hasState = false;
disposable.setDisposable(scheduler.scheduleRecursiveWithState(null,
function(state, self) {
hasState && observer.onNext(state);
hasState = false;
next().subscribe(function(x){
hasState = true;
self(x);
}, observer.onError.bind(observer));
}));
return disposable;
});
};
The idea here is that you can schedule new items once the previous one has completed. You call next() which invokes the passed in method and when it returns a value, you schedule the next item for invocation.
You can then use it like so:
Rx.Observable.forever(getNextMessage)
.take(11)
.subscribe(function(message) {
console.log(message);
});
See a working example here
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);