How to bind multiple properties in one calculate in GoJS? - javascript

I have a simple demo like the one below:
const calcProperty = (data) => {
//Some complex calculate
return {
text: '...',
stroke: "..."
}
}
const calcText = (data) => {
return calcProperty(data).text;
}
const calcStroke = (data) => {
return calcProperty(data).stroke;
}
$(go.TextBlock, {
text: 'refresh', //Default
stroke: 'red', // Default
},
new go.Binding("text", "", calcText),
new go.Binding("stroke", "", calcStroke),
),
As you can see, the complex calculations have to run twice.
Is that anyway I can do something like this, and it automatic to apply to properties?
new go.Binding("dynamic or something", "", (data) => {
//Some complex calculate
return {
text: '...',
stroke: "..."
}
}),

You could set the properties, once calculated, on the Node's data object, and also set a flag.
const calcProperty = (data) => {
if (data.calculated) return data; // already run
data.calculated = true;
//Some complex calculations that ALSO set:
data.text = "...";
data.stroke = "...";
return data;
}
Of course, you will need to handle cache invalidation if you go this route.
Note also that empty-string bindings re-run every time any of the data changes. If this is intended to be a one-time thing it shouldn't be a data binding at all, it should be computed before the node data is even added to the model, and the data bindings should be simple bindings instead.

Related

Infinite functions calls like 'string'.replace().replace()

I'm not really sure how to explain so I will start with the output.
I need to return this:
{
replies:
[
{ type: 'text', content: 'one' }
{ type: 'text', content: 'two' }
{ type: 'text', content: 'three' }
],
conversation: {
memory
}
}
And I wanted to return that through in-line statement.
So I would like to call something like:
reply.addText('one').addText('two').addText('three').addConversation(memory)
Note that addText can be called infinite times while addConversation can be called only one time. Also conversation is optional, in that case, if conversation is absent the conversation object should not appear in the output.
To create a custom structured object use a constructor, say Reply.
To call instance methods on the return value of method calls, return the instance object from the method.
Choices to prevent multiple additions of conversation objects include throwing an error (as below) or perhaps logging a warning and simply not add additional objects after a first call to addConversation.
Write the code to implement the requirements.
For example using vanilla javascript:
function Reply() {
this.replies = [];
}
Reply.prototype.addText = function( content) {
this.replies.push( {type: "text", content: content});
return this;
}
Reply.prototype.addConversation = function( value) {
if( this.conversation) {
//throw new Error("Only one conversation allowed");
}
this.conversation = {conversation: value};
return this;
};
Reply.prototype.conversation = null;
// demo
var reply = new Reply();
reply.addText( "one").addText("two").addConversation("memory?");
console.log( JSON.stringify( reply, undefined," "));
(The console.log uses JSON stringify to avoid listing inherited methods)
A possible implementation is to create a builder as follows:
function create() {
const replies = []; // store all replies in this array
let conversation; // store the memory here
let hasAddConversationBeenCalled = false; // a state to check if addConversation was ever called
this.addText = function(content) {
// add a new reply to the array
replies.push({
type: 'text',
content
});
return this; // return the builder
};
this.addConversation = function(memory) {
if (!hasAddConversationBeenCalled) { // check if this was called before
// if not set the memory
conversation = {
memory
};
hasAddConversationBeenCalled = true; // set that the memory has been set
}
return this; // return the builder
}
this.build = function() {
const reply = {
replies
};
if (conversation) { // only if converstation was set
reply.conversation = conversation; // add it to the final reply object
}
return reply; // finally return the built respnse
}
return this; // return the new builder
}
You can then use it as follows:
const builder = create();
const reply = builder.addText('one').addText('two').addText('three').addConversation({}).build();
Here is a link to a codepen to play around with.
If you specifically want to add assemble this via multiple function calls, then the builder pattern is your best bet, as vader said in their comment.
However, if the goal is to simply create shorthand for concisely building these objects, it can be done using a function that takes the list of text as an array.
const buildObject = (textArray, memory) => {
return Object.assign(
{},
{
replies: textArray.map(x => {
return {
type: 'text',
value: x
}
})
},
memory ? {conversation: memory} : null
)
}
var memory = { };
//with memory
console.log(buildObject(['one', 'two', 'three'], memory ))
//without memory
console.log(buildObject(['one', 'two', 'three']));
Fiddle example: http://jsfiddle.net/ucxkd4g3/

Passing gathered value in API call from first method to second in same object

I have a object which contains two methods. The first one is calling API and storing response in variable.
In second method I execute first one using this.nameOfFirstMethod() and then I want to do some calculation basing on numbers which I collected in API call in first method.
To make it more clear take a look at code, start reading at second method:
this.currencyConverter = {
getRatio: function(selectedCurrency) {
var selectedCurrency = selectedCurrency;
$http({
url: 'http://api.fixer.io/latest?base='+selectedCurrency+'&symbols=PLN,CHF,EUR,USD,GBP',
method: 'GET'
})
.then(function(response) {
var currentCurrency = {
toPLN: response.data.rates.PLN,
toCHF: response.data.rates.CHF,
toEUR: response.data.rates.EUR,
toUSD: response.data.rates.USD,
toUSD: response.data.rates.GBP
};
console.log("Succesful store currentCurrency");
return currentCurrency;
}, function(response) {
console.log("Problem occure while downloading money current currency!");
console.log(response.data);
});
},
convertMoney: function(selectedCurrency,priceField) {
var priceField = priceField;
var selectedCurrency = selectedCurrency;
console.log('selectedCurrency in service: '+selectedCurrency);
console.log('priceField in service: '+priceField);
this.getRatio(selectedCurrency);
console.log(currentCurrency);
/*
var converted = {
PLN: function() { return priceField * $rootScope.currentCurrency.toPLN; },
USD: function() { return priceField * $rootScope.currentCurrency.toUSD; },
EUR: function() { return priceField * $rootScope.currentCurrency.toEUR; },
CHF: function() { return priceField * $rootScope.currentCurrency.toCHF; },
GBP: function() { return priceField * $rootScope.currentCurrency.toGBP; }
};
*/
}
}
Here is GIST of same code if someone doesn't like StackOverflow styling:
https://gist.github.com/anonymous/e03de4de1af407bf70f4038acd77c961
Please open this gist because I will now explain basing on specific line.
So in the line 30 I execute first method.
In line 9 I'm storing retrieved data in variable and in line 17 returning this data (in order to use it in second method).
Finally I want to console.log this in second object in line 32 (for now only console.log I will do my maths later on).
It doesn't work with this return, the line with console.log in second method cause following error:
ReferenceError: currentCurrency is not defined
you don't assign the return value of getRatio to a variable
it should be
currentCurrency = this.getRatio(selectedCurrency);
And you should work with promises correctly.
So change it to something like this (not tested)
this.currencyConverter = {
getRatio: function(selectedCurrency) {
var selectedCurrency = selectedCurrency;
return $http({
url: 'http://api.fixer.io/latest?base='+selectedCurrency+'&symbols=PLN,CHF,EUR,USD,GBP',
method: 'GET'
})
.then(function(response) {
var currentCurrency = {
toPLN: response.data.rates.PLN,
toCHF: response.data.rates.CHF,
toEUR: response.data.rates.EUR,
toUSD: response.data.rates.USD,
toUSD: response.data.rates.GBP
};
console.log("Succesful store currentCurrency");
return currentCurrency;
}, function(response) {
console.log("Problem occure while downloading money current currency!");
console.log(response.data);
});
},
convertMoney: function(selectedCurrency,priceField) {
var priceField = priceField;
var selectedCurrency = selectedCurrency;
console.log('selectedCurrency in service: '+selectedCurrency);
console.log('priceField in service: '+priceField);
var currentCurrency = this.getRatio(selectedCurrency);
currentCurrency.then(res => console.log(res));
//console.log(currentCurrency);
}
}

How can I pass an data from factory to my controller in angularjs?

I'm trying to move all the business logic from my controller to the factory, but I'm having some trouble passing fields data.
factory.js
app.factory("Quote", function ($resource) {
// TODO: this shouldn't start with /en/
var quoteStatus = [];
var quoteLanguage = [];
var Quote = $resource("/en/quote/api/quote/:id", {}, {
retrieve: {
method: 'GET',
params: {},
isArray: true
},
query: {
method: 'GET',
params: {},
isArray: true,
url: '/en/quote/api/quote/'
},
fields: {
method: 'GET',
url: '/en/quote/api/quote/fields/ '
},
update: {
method: 'PATCH',
},
});
Quote.fields().$promise.then(function (fields) {
var tempObj = [];
for (key in fields.status) {
// must create a temp object to set the key using a variable
tempObj[key] = fields.status[key];
quoteStatus.push({
value: key,
text: tempObj[key]
});
}
for (key in fields.language) {
// must create a temp object to set the key using a variable
tempObj[key] = fields.language[key];
quoteLanguage.push({
value: key,
text: tempObj[key]
});
}
//$scope.addLanguage($scope.language);
Quote.status = quoteStatus;
Quote.language = quoteLanguage;
});
return Quote;
});
controller.js
$scope.quoteStatus = Quote.status;
However this is not working since $scope.quoteStatus is undefined. What am I missing?
Thanks in advance.
You can't expect async operation to behave in synchronous way.
Basically when controller inject Quote in its factory function that time Quote service object gets created & then calls Quote.fields(). hen you ask Quote.status inside a controller will always return undefined. You are not maintaining promise anywhere so that controller will come to know that the data is ready or not.
I think you should introduce $q.when flag there to check the Quote.fields() operation completed or not & then do get the desired variable there.
For implementing above mention thing you need to store the promise of Quote.fields() call somewhere in service. like below
var quoteFieldsPromise = Quote.fields().$promise.then(function (fields) {
/// the code will be same here
};
Then add new method which will hold of quoteFieldsPromise promise object and return the value of quoteStatus & quoteLanguage.
var getQuoteDetails = function(){
$q.when(quoteFieldsPromise).then(function(){
return { quoteStatus: Quote.quoteStatus, quoteLanguage: Quote.quoteLanguage };
})
}
But the way you have returned whole Quote object, which only has $resource object which needs to be changed. I mean to say that the getQuoteDetails method which I've created can not be return with Quote object. So I'd rather rather refactor service to below.
Service
app.factory("Quote", function($resource, $q) {
// TODO: this shouldn't start with /en/
var quoteStatus = [], //kept private if needed
quoteFieldsPromise,
quoteLanguage = [];//kept private if needed
var QuoteApi = $resource("/en/quote/api/quote/:id", {}, {
//inner code is as is
});
//preserve promise of .fields() call
quoteFieldsPromise = Quote.fields().$promise.then(function(fields) {
//inner code is as is
//below lines are only changed.
Quote.status = quoteStatus;
Quote.language = quoteLanguage;
});
var getQuoteDetails = function() {
return $q.when(quoteFieldsPromise).then(function() {
return {
quoteStatus: quoteStatus,
quoteLanguage: quoteLanguage
};
})
};
return {
QuoteApi: QuoteApi,
getQuoteDetails: getQuoteDetails
};
});
Controller
Quote.getQuoteDetails().then(function(quoteDetails){
$scope.quoteStatus = quoteDetails.quoteStatus;
$scope.quoteStatus = quoteDetails.quoteLanguage;
});

Mithril - how to populate drop down list of view from API

I'm trying to populate a drop down box rendered by Mithril's view from methods being called outside of its module (not sure if this terminology is correct, but outside of the property which contains the view, model and controller).
This Chrome extension adds a new field to an existing page and depending on what the user select, the drop down box should refresh to items pertaining to the selected item. I can get up to the stage of getting the new list of items, but i cannot get the drop down list to redraw with the new objects.
The following shows the module which gets inserted inside an existing page:
var ItemsList = {
model: function () {
this.list = function (id) {
var d = m.deferred()
// Calls Chrome extension bg page for retrieval of items.
chromeExt.getItems(pId, function (items) {
// Set default values initially when the controller is called.
if (items.length === 0) {
items = [
{name: 'None', value: 'none'}
]
}
d.resolve(items || [])
})
return d.promise
}
},
controller: function () {
this.model = new ItemsList.model()
this.index = m.prop(0)
this.onchange = function (e) {
console.info('ctrl:onchange', e.target)
}
// Initialise the drop down list array list.
this.dropDownItemsList = m.prop([]);
// This sets the default value of the drop down list to nothing by calling the function in the model,
// until the user selects an item which should populate the drop down list with some values.
this.getItems = function(pId) {
this.model.list(pId).then(function (data) {
this.dropDownItemsList(data)
m.redraw()
}.bind(this))
}
this.getItems(0);
},
view: function (ctrl) {
var SELECT_ID = 'record_select'
return vm.Type() ? m('div', [
m('.form__item', [
m('.label', [
m('label', {
htmlFor: SELECT_ID
}, 'ID')
]),
m('.field', [
m('select#' + SELECT_ID, {
onchange: ctrl.onchange.bind(ctrl)
},
ctrl.dropDownItemsList().map(function (it, i) {
return m('option', {
value: it.value,
checked: ctrl.model.index === i
}, it.name)
})
),
])
]),
]) : null
}
}
And it is mounted using
m.mount("element name here", ItemsList);
The code which checks to see if the item has changed is using a mutation observer, and whenever it detects changes to a certain field, it will call a method to get the new values. I can see that the return value has my new items.
I have tried various different methods on trying to update the drop down list, first by trying to set the "this.list" with the new items list i've got, or trying to create a returnable method on the controller which i can call when the mutation observer fires.
After getting the new items, how can i make the drop down list show the new items which has been retrieved?
I have read guides which shows functions in the controller or model being run - but only if they've been defined to use them already in the view (i.e. have an onclick method on the view which calls the method) but so far i cannot figure out how to update or call methods from outside of the module.
Is there a way to achieve the above or a different method i should approach this?
After some more research into how Mithril works, seems like that it's not possible to call any functions defined within the component.
Due to this, i have moved the model outside of the component (so now it only has the controller and the view defined) and bound the view to use the model outside of the component.
Now calling a function which updates the model (which is now accessible from elsewhere in the code) and redrawing shows the correct values that i need.
If I understand correctly, you need to have two variables to store your lists, one to store the old list and one to store the updated list so you can always map the updated one and go to your old one if you need.
Here is a simple implementation of a drop down list with some methods to update and search. You can update the list on the fly using the methods.
mithDropDown
jsFiddle
var MythDropDown = function(list) {
if (Array.isArray(list))
this.list = list;
else
list = [];
if (!(this instanceof MythDropDown))
return new MythDropDown(list);
var self = this;
this.selected = {
name: list[0],
index: 0
};
this.list = list;
};
MythDropDown.prototype.view = function(ctrl) {
var self = this;
return m('select', {
config: function(selectElement, isinit) {
if (isinit)
return;
self.selectElement = selectElement;
self.update(self.list);
},
onchange: function(e) {
self.selected.name = e.target.value;
self.selected.index = e.target.selectedIndex;
}
},
this.list.map(function(name, i) {
return m('option', name);
}));
};
MythDropDown.prototype.getSelected = function() {
return (this.selected);
};
MythDropDown.prototype.update = function(newList) {
this.list = newList;
this.selectElement.selectedIndex = 0;
this.selected.name = newList[0];
this.selected.index = 0;
};
MythDropDown.prototype.sort = function() {
this.list.sort();
this.update(this.list);
};
MythDropDown.prototype.delete = function() {
this.list.splice(this.selected.index, 1);
this.update(this.list);
};
var list = ['test option 1', 'test option 2'];
var myList = new MythDropDown(list);
var main = {
view: function() {
return m('.content',
m('button', {
onclick: function() {
var L1 = ['Banana', 'Apple', 'Orange', 'Kiwi'];
myList.update(L1);
}
},
'Fruits'),
m('button', {
onclick: function() {
var L1 = ['Yellow', 'Black', 'Orange', 'Brown', 'Red'];
myList.update(L1);
}
},
'Colors'),
m('button', {
onclick: function() {
myList.sort();
}
},
'Sort'),
m('button', {
onclick: function() {
myList.delete();
}
},
'Remove Selected'),
m('', m.component(myList),
m('', 'Selected Item: ' + myList.selected.name, 'Selected Index: ' + myList.selected.index)
)
);
}
};
m.mount(document.body, main);
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.3/mithril.min.js"></script>

Using Flux to build an edit form, who actually POSTs data to the server: actions, stores, views?

I have found a lot of resources, blogs, and opinions on how to fetch data for React and Flux, but much less on writing data to the server. Can someone please provide a rationale and some sample code for the "preferred" approach, in the context of building a simple edit form that persists changes to a RESTful web API?
Specifically, which of the Flux boxes should call $.post, where is the ActionCreator.receiveItem() invoked (and what does it do), and what is in the store's registered method?
Relevant links:
Should the action or store be responsible for transforming data when using React + Flux?
Should flux stores, or actions (or both) touch external services?
Where should ajax request be made in Flux app?
Short answer
Your form component should retrieve its state from Store, create "update" action on user inputs, and call a "save" action on form submit.
The action creators will perform the POST request and will trigger a "save_success" action or "save_error" action depending on the request results.
Long answer via implementation example
apiUtils/BarAPI.js
var Request = require('./Request'); //it's a custom module that handles request via superagent wrapped in Promise
var BarActionCreators = require('../actions/BarActionCreators');
var _endpoint = 'http://localhost:8888/api/bars/';
module.exports = {
post: function(barData) {
BarActionCreators.savePending();
Request.post(_endpoint, barData).then (function(res) {
if (res.badRequest) { //i.e response returns code 400 due to validation errors for example
BarActionCreators.saveInvalidated(res.body);
}
BarActionCreators.savedSuccess(res.body);
}).catch( function(err) { //server errors
BarActionCreators.savedError(err);
});
},
//other helpers out of topic for this answer
};
actions/BarActionCreators.js
var AppDispatcher = require('../dispatcher/AppDispatcher');
var ActionTypes = require('../constants/BarConstants').ActionTypes;
var BarAPI = require('../apiUtils/VoucherAPI');
module.exports = {
save: function(bar) {
BarAPI.save(bar.toJSON());
},
saveSucceed: function(response) {
AppDispatcher.dispatch({
type: ActionTypes.BAR_SAVE_SUCCEED,
response: response
});
},
saveInvalidated: function(barData) {
AppDispatcher.dispatch({
type: ActionTypes.BAR_SAVE_INVALIDATED,
response: response
})
},
saveFailed: function(err) {
AppDispatcher.dispatch({
type: ActionTypes.BAR_SAVE_FAILED,
err: err
});
},
savePending: function(bar) {
AppDispatcher.dispatch({
type: ActionTypes.BAR_SAVE_PENDING,
bar: bar
});
}
rehydrate: function(barId, field, value) {
AppDispatcher.dispatch({
type: ActionTypes.BAR_REHYDRATED,
barId: barId,
field: field,
value: value
});
},
};
stores/BarStore.js
var assign = require('object-assign');
var EventEmitter = require('events').EventEmitter;
var Immutable = require('immutable');
var AppDispatcher = require('../dispatcher/AppDispatcher');
var ActionTypes = require('../constants/BarConstants').ActionTypes;
var BarAPI = require('../apiUtils/BarAPI')
var CHANGE_EVENT = 'change';
var _bars = Immutable.OrderedMap();
class Bar extends Immutable.Record({
'id': undefined,
'name': undefined,
'description': undefined,
'save_status': "not saved" //better to use constants here
}) {
isReady() {
return this.id != undefined //usefull to know if we can display a spinner when the Bar is loading or the Bar's data if it is ready.
}
getBar() {
return BarStore.get(this.bar_id);
}
}
function _rehydrate(barId, field, value) {
//Since _bars is an Immutable, we need to return the new Immutable map. Immutable.js is smart, if we update with the save values, the same reference is returned.
_bars = _bars.updateIn([barId, field], function() {
return value;
});
}
var BarStore = assign({}, EventEmitter.prototype, {
get: function(id) {
if (!_bars.has(id)) {
BarAPI.get(id); //not defined is this example
return new Bar(); //we return an empty Bar record for consistency
}
return _bars.get(id)
},
getAll: function() {
return _bars.toList() //we want to get rid of keys and just keep the values
},
Bar: Bar,
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener: function(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
});
var _setBar = function(barData) {
_bars = _bars.set(barData.id, new Bar(barData));
};
BarStore.dispatchToken = AppDispatcher.register(function(action) {
switch (action.type)
{
case ActionTypes.BAR_REHYDRATED:
_rehydrate(
action.barId,
action.field,
action.value
);
BarStore.emitChange();
break;
case ActionTypes.BAR_SAVE_PENDING:
_bars = _bars.updateIn([action.bar.id, "save_status"], function() {
return "saving";
});
BarStore.emitChange();
break;
case ActionTypes.BAR_SAVE_SUCCEED:
_bars = _bars.updateIn([action.bar.id, "save_status"], function() {
return "saved";
});
BarStore.emitChange();
break;
case ActionTypes.BAR_SAVE_INVALIDATED:
_bars = _bars.updateIn([action.bar.id, "save_status"], function() {
return "invalid";
});
BarStore.emitChange();
break;
case ActionTypes.BAR_SAVE_FAILED:
_bars = _bars.updateIn([action.bar.id, "save_status"], function() {
return "failed";
});
BarStore.emitChange();
break;
//many other actions outside the scope of this answer
default:
break;
}
});
module.exports = BarStore;
components/BarList.react.js
var React = require('react/addons');
var Immutable = require('immutable');
var BarListItem = require('./BarListItem.react');
var BarStore = require('../stores/BarStore');
function getStateFromStore() {
return {
barList: BarStore.getAll(),
};
}
module.exports = React.createClass({
getInitialState: function() {
return getStateFromStore();
},
componentDidMount: function() {
BarStore.addChangeListener(this._onChange);
},
componentWillUnmount: function() {
BarStore.removeChangeListener(this._onChange);
},
render: function() {
var barItems = this.state.barList.toJS().map(function (bar) {
// We could pass the entire Bar object here
// but I tend to keep the component not tightly coupled
// with store data, the BarItem can be seen as a standalone
// component that only need specific data
return <BarItem
key={bar.get('id')}
id={bar.get('id')}
name={bar.get('name')}
description={bar.get('description')}/>
});
if (barItems.length == 0) {
return (
<p>Loading...</p>
)
}
return (
<div>
{barItems}
</div>
)
},
_onChange: function() {
this.setState(getStateFromStore();
}
});
components/BarListItem.react.js
var React = require('react/addons');
var ImmutableRenderMixin = require('react-immutable-render-mixin')
var Immutable = require('immutable');
module.exports = React.createClass({
mixins: [ImmutableRenderMixin],
// I use propTypes to explicitly telling
// what data this component need. This
// component is a standalone component
// and we could have passed an entire
// object such as {id: ..., name, ..., description, ...}
// since we use all the datas (and when we use all the data it's
// a better approach since we don't want to write dozens of propTypes)
// but let's do that for the example's sake
propTypes: {
id: React.PropTypes.number.isRequired,
name: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired
}
render: function() {
return (
<li> //we should wrapped the following p's in a Link to the editing page of the Bar record with id = this.props.id. Let's assume that's what we did and when we click on this <li> we are redirected to edit page which renders a BarDetail component
<p>{this.props.id}</p>
<p>{this.props.name}</p>
<p>{this.props.description}</p>
</li>
)
}
});
components/BarDetail.react.js
var React = require('react/addons');
var ImmutableRenderMixin = require('react-immutable-render-mixin')
var Immutable = require('immutable');
var BarActionCreators = require('../actions/BarActionCreators');
module.exports = React.createClass({
mixins: [ImmutableRenderMixin],
propTypes: {
id: React.PropTypes.number.isRequired,
name: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired
},
handleSubmit: function(event) {
//Since we keep the Bar data up to date with user input
//we can simply save the actual object in Store.
//If the user goes back without saving, we could display a
//"Warning : item not saved"
BarActionCreators.save(this.props.id);
},
handleChange: function(event) {
BarActionCreators.rehydrate(
this.props.id,
event.target.name, //the field we want to rehydrate
event.target.value //the updated value
);
},
render: function() {
return (
<form onSubmit={this.handleSumit}>
<input
type="text"
name="name"
value={this.props.name}
onChange={this.handleChange}/>
<textarea
name="description"
value={this.props.description}
onChange={this.handleChange}/>
<input
type="submit"
defaultValue="Submit"/>
</form>
)
},
});
With this basic example, whenever the user edits a Bar item via the form in BarDetail component, the underlying Bar record will be maintained up to date locally and when the form is submitted we try to save it on the server. That's it :)
Components/Views are used to display data and fire events
Actions are tied to the events (onClick, onChange...) and are used to communicate with resources and dispatch events once the promise has been resolved or failed. Make sure you have at least two events, one for success and one for ajax failed.
Stores are subscribed to the events dispatcher is dispatching. Once data is received stores are updating the values which are stored and emitting changes.
Components/Views are subscribed to the stores and are re-rendering once the change has happened.
Should flux stores, or actions (or both) touch external services? approach is what seems natural to me.
Also there are cases when you need to trigger some action as a result of some other action being triggered, this is where you can trigger actions from a relevant store, which results store and views being updated.

Categories

Resources