I am trying to store the settings into the global variable.
var settings= {};
function on_ready() {
Ext.Ajax.request({
url: baseURL,
success: function(response) {
settings = Ext.decode(response.responseText);
},
failure: function(response) {
console.log('server-side failure with status code ' + response.status);
}
});
}
console.log(settings);
The last line of code shows empty. I know that this is asynchronous call and thus it does not work. But don't know the solution. Is there a way how can I do this? I need to use this ˙settings˙ variable throughout my application. That's why it has to be global.
One approach we have used in the past for initializing settings before app start was using server-side templating for the html file. It did nothing more, but simply add a <script> block, and populated it with lines like window['prefix_propname'] = 'propvalue';. Not the most elegant way, but it worked fine.
But first, I'd rethink if you truly need it to be global. It's likely that you could simply have a data field in main's viewmodel with the settings (which are loaded on init of the main's controller), and then bind setting's parts as needed to the children via their config. Logic depending on the settings value then would be either in child's config update / apply methods, expressed via formulas with the settings as one of the parameters, or via a bind (inside view or controller). The bindings inside controller is a very handy feature, which comes up fairly often in my use, and it abstracts away the annoyance of having to deal with async loading; e.g.:
// view controller
init: function() {
var vm = this.getViewModel();
vm.bind('{settings}', function(settings) {
//do your thing here
});
}
All you need is a extjs singleton. Get the instance of singleton inside the success function and assign your settings to that singleton. Also there is an easier way to add singleton, i.e by adding settings in your window object.
success: function(response) {
window["settings"] = Ext.decode(response.responseText);
}
Now you should be able to access the settings globally across the application.Still console.log will not have actual value because the will be other thread created for ajax call the present exection will continue without waiting for success function. You type "settings" after execution of "success" you'll see the contents.
Related
I am just trying to get my head around event driven JS, so please bear with me. There are different kinds of modules within my app. Some just encapsulate data, others manage a part of the DOM. Some modules depend on others, sometimes one module depends on the state of multiple other modules, but I don't want them to communicate directly or pass one module to the other just for easy access.
I tried to create the simplest scenario possible to illustrate my problem (the actual modules are much more complex of course):
I have a dataModule that just exposes some data:
var dataModule = { data: 3 };
There is a configModule that exposes modifiers for displaying that data:
var configModule = { factor: 2 };
Finally there is a displayModule that combines and renders the data from the two other modules:
var displayModule = {
display: function(data, factor) {
console.log(data * factor);
}
};
I also have a simple implementation of pub-sub, so I could just mediate between the modules like this:
pubsub.subscribe("init", function() {
displayModule.display(dataModule.data, configModule.factor);
});
pubsub.publish("init"); // output: 6
However this way I seem to end up with a mediator that has to know all of the module-instances explicitly - is there even a way to avoid that? Also I don't know how this would work if there are multiple instances of these modules. What is the best way to avoid global instance-variables? I guess my question is what would be the most flexible way to manage something like that? Am I on the right track, or is this completely wrong? Sorry for not being very precise with my question, I just need someone to push me in the right direction.
You are on the right track, I'll try to give you that extra push you're talking about:
It you want loose coupling, pub-sub is a good way to go.
But, you don't really need that "mediator", each module should ideally be autonomous and encapsulate its own logic.
This is done in the following way: each module depends on the pubsub service, subscribe to all relevant events and act upon them. Each module also publishes events which might be relevant to others (code samples in a minute, bear with me).
I think the bit you might be missing here is that modules, which use events, will hardly never be just plain models. They will have some logic in them and can also hold a model (which they update when receiving events).
So instead of a dataModule you are more likely to have a dataLoaderModule which will publish the data model (e.g. {data: 3}), once he finishes loading.
Another great requirement you set is sharing data while avoiding global instance-variables - this is a very important concept and also a step in the right direction. What you miss in your solution for this is - Dependency Injection or at least a module system which allows defining dependencies.
You see, having an event driven application doesn't necessarily mean that every piece of the code should communicate using events. An application configuration model or a utility service is definitely something I would inject (when using DI, like in Angular), require (when using AMD/CommonJS) or import (when using ES6 modules).
(i.e. rather then communicating with a utility using events).
In your example it's unclear whether configModule is a static app configuration or some knob I can tweak from the UI. If it's a static app config - I would inject it.
Now, let's see some examples:
Assuming the following:
Instead of a dataModule we have a dataLoaderModule
configModule is a static configuration model.
We are using AMD modules (and not ES6 modules, which I prefer), since I see you stuck to using only ES5 features (I see no classes or consts).
We would have:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
configuration.js (aka configModule)
define([], function () {
return {factor: 2};
});
display.js (aka displayModule)
define(['configuration', 'pubsub'], function (configuration, pubsub) {
var displayModule = {
display: function (data, factor) {
console.log(data * factor);
}
};
pubsub.subscribe('data-loaded', function (data) {
displayModule.display(data, configuration.factor);
});
});
That's it.
You will notice that we have no global variables here (not even pubsub), instead we are requiring (or injecting) our dependencies.
Here you might be asking: "and what if I meant for my config to change from the UI?", so let's see that too:
In this case, I rather rename configModule to settingsDisplayModule (following your naming convention).
Also, in a more realistic app, UI modules will usually hold a model, so let's do that too.
And lets also call them "views" instead of "displayModules", and we will have:
data-loader.js (aka dataLoaderModule)
define(['pubsub'], function (pubsub) {
// ... load data using some logic...
// and publish it
pubsub.publish('data-loaded', {data: 3});
});
settings-view.js (aka settingsDisplayModule, aka config)
define(['pubsub'], function (pubsub) {
var settingsModel = {factor: 2};
var settingsView = {
display: function () {
console.log(settingsModel);
// and when settings (aka config) changes due to user interaction,
// we publish the new settings ...
pubsub.publish('setting-changed', settingsModel);
}
};
});
data-view.js (aka displayModule)
define(['pubsub'], function (pubsub) {
var model = {
data: null,
factor: 0
};
var view = {
display: function () {
if (model.data && model.factor) {
console.log(model.data * model.factor);
} else {
// whatever you do/show when you don't have data
}
}
};
pubsub.subscribe('data-loaded', function (data) {
model.data = data;
view.display();
});
pubsub.subscribe('setting-changed', function (settings) {
model.factor = settings.factor;
view.display();
});
});
And that's it.
Hope it helps :)
If not - comment!
You do not need a mediator. Just import data, config, and display and call display(data, config) where you need to.
// import data
// import config
function render(){
display(data, config)
}
I curious if there is any agreed upon pattern to check if data has been already loaded before hitting the server.
Say I have my action that looks like this:
Actions.loadRequest.preEmit = function () {
$.get('/store/', function (data) {
Actions.loadSuccess(data);
}.bind(this));
}
This is called from a component that is simply saying give me this data:
But I don't want to hit the server if that data is already in the store.
Should I store the logic of checking the store in the component:
render: function () {
var data = this.state.store.data;
if (!data) {
Actions.loadRequest();
}
Is there a better way to go about this?
In my project I use shouldEmit for this (see https://github.com/reflux/refluxjs#action-hooks). An example from my code:
var streamStore = Reflux.createStore({
[...]
});
actions.loadStream.shouldEmit = function(streamId) {
if(streamId in streamStore.data)
return false;
return true;
};
This lives in the same file as the store definition. I think this is conceptually the right approach because the store saves the data, so the store should be responsible for intercepting the request to load more data and saying not to, just as it's responsible for listening to the action saying more data is available and updating itself.
Unfortunately this won't work with your example because you bound the AJAX call to preEmit, which gets called before shouldEmit. I would suggest refactoring to make the API call in a normal listen call, like this:
Actions.loadRequest.listen(function () {
$.get('/store/', function (data) {
Actions.loadSuccess(data);
}.bind(this));
});
This saves preEmit for the rare case of needing to rewrite an action's arguments before emitting it. I do use this pattern in my code, for example when loading a second page of results, which relies on a next token that came with the first page and is thus in the store. But in the general simple case of "action triggered, so make a request", using listen makes more sense because then you can add preEmit and shouldEmit for more advanced behavior, like the caching you want.
Reflux also has a helper function, listenAndPromise, which further simplifies the common use case of "action fired, make AJAX call, then fire another action when it's done". Your example could become:
Actions.loadRequest.listenAndPromise(function () {
return $.get('/store/');
});
See this section of the docs for more info on how to set that up: https://github.com/reflux/refluxjs#asynchronous-actions
I'm not sure if i have completely wrapped my head around this idea - but I'll try my best to clearly describe what I am trying to do here.
I have a factory that changes and parses a URL for me, so I can pass params into a controller for use (that were stored in the url). This is sort of so I can save a state for the user and they can share it via copy'ing of a URL (send it to their friends or bookmark it or w/e).
I am trying to set up a factory (or service) that listens for locationChangeSuccess - so that if the user mofies the url and presses enter, it will refresh the scopes in the controllers. So here is what I have:
.factory("urlFactory", function($location, freshUrl, StateString){
//request to change new url
requestObj.requestState = function(moduleName, stateName, startVar){
}
//request item from url, via your module and state name
requestObj.parseState = function(moduleName, stateName){
}
I dropped the center out (if it is needed im happy to link), but those just get and set the url for me.
So in the controllers I do something like
$scope.mod2m3 = urlFactory.parseState("module2", "mod3");
$scope.mod2m4 = urlFactory.parseState("module2", "mod4");
So when they land on the page, they pull their state. This works great. However, now i'm trying to solve some edge case scenarios where maybe the user modifies the url.
So I can latch onto that even pretty easily with
.factory("urlWatcher", function($location, $scope){
var urlWatcher = {};
$scope.$on('$locationChangeSuccess', function(event) {
console.log("Asdsa");
});
return urlWatcher
});
However, where I am struggling is trying to determine a way where when this fires, it would connect the new value to the scope in the controller. It was suggested to me that a callback of some sort in the parse (set) function, but I am struggling with how to approach that. It would be super cool if I could set a way for this factory/service to re send the new value when it changes to the right place. Callback sounds good, however I don't know how to config this correct.
The easiest route would be to just do an
$scope.$on('$locationChangeSuccess', function(event) {
console.log("Asdsa");
});
In each controller and manually bind to each scope, but I am trying to make this as modular as possible (and thats also a ton of watchers on the locationchangesuccess). would be fantastic if I could figuire out a clean way to set the service/factory to listen once, and on change find the right module/controller and change the value.
I can't seem to think a clear route, so I would be very greatful for any insight to this issue. Thank you very much for reading!
If what you want is a publish/subscribe architecture, where publications are global and subscriptions have the same lifecycles as Angular scopes... then Angular events are what you're looking for. There's no point setting up an ad hoc communication system with callbacks and whatnut, that would just be partially reinventing events.
However, if you want to make the semantics more obvious / add flexibility, you can listen once to $locationChangeSuccess in a service and broadcast a custom event.
$rootScope.$on("$locationChangeSuccess", function (event) {
$rootScope.$broadcast('myCustomeEvent', {message: "Guys, time to refresh!"});
});
Then listen to this event in each of the scopes where it is relevant.
$scope.$on('myCustomeEvent', function (event) {
console.log("Asdsa");
});
If setting up the listening gets repetitive, by all means, factor it out in a function, which you can for example put in a service:
myApp.factory('someFactory', [function () {
return {
listenToLogAsdsa: function (scope) {
scope.$on('myCustomeEvent', function (event) {
console.log("Asdsa");
});
}
};
}]);
Then all you have to write in your controller is:
someFactory.listenToLogAsdsa($scope);
You can assign a variable in the scope to an object in the factory, that way it's bound to a reference instead of a value. Then, in your HTML you bind the reference to the DOM. urlFactory.parseState() should then save the result to said object, and return the key where it was saved.
For example:
In urlFactory:
requestObj.parseState = function(moduleName, stateName){
var key = moduleName+stateName;
this.urlContainer[key] = "www.example.com";
return key;
}
In the controller:
$scope.urls = urlFactory.urlContainer;
$scope.mod2m3 = urlFactory.parseState("module2", "mod3");
In your HTML:
{{urls[mod2m3]}}
This way, "urls" is bound to a reference, which angular watches for changes, and whenever you change urls[mod2m3], it will affect the DOM.
You can also just react to changes in the scope variables by watching them:
$scope.$watch('urls', function() {
//do something
});
NOTE: Since this is an object, you might need to use $watchCollection instead of $watch.
// Main class
function App() {
this.task = new Task(this); // pass the instance of this class to Task so
// it has access to doSomething
}
App.prototype.doSomething = function () {
alert("I do something that Task() needs to be able to do!");
};
function Task(app) {
// This class needs access to App()'s doSomething method
this.appInstance = app;
this.appInstance.doSomething(); // Great, now Task can call the method
}
var app = new App();
The aim of the code above is to give Task access to one of App's methods called doSomething. The code is the current way I'd go about it and I'm posting this to see if it's the best way...
To give Task access I simply pass the whole instance of App, is this efficient or is there a better way to go about it? Is the code above general practice in going about doing something like this?
Yes, what you have is fine. It is a circular dependency, however because of JavaScript's dynamic nature there aren't really any issues.
Another way you could reference App from Task would be a Singleton pattern or something similar, but that would probably be harder to test.
jsFiddle Demo
Generally bind would be used in this scenario assuming that the Task "class" didn't also setup other facilities which were not shown here.
Bind allows for the context to be provided for a function. This could be done in app's constructor. At which point only a function task would be required to call "someMethod".
function task(){
return this["someMethod"]();
}
function App(){
task.bind(this)();
}
App.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
However, if task must be a "class", and have other responsibilities then the prototype function could be shared.
function Task(){}
function App(){}
App.prototype.someMethod = Task.prototype.someMethod = function(){
alert("Task needed access to this");
};
var a = new App();
a.task();//->"Task needed access to this"
var t = new Task();
t.someMethod();//->"Task needed access to this"
Your app instances and task instances are tightly bound. App instances have tasks and this can be fine.
A design of loosely coupled objects is more flexible and easier to extend but more complicated to initially create. One such pattern is using a mediator/publish subscriber and have app raise an event/publish message any other object function can listen to this and take action on the event.
For example: your app creates an Ajax instance and when that instance is done it raises some event (fetchedData for example). A listener could be DomDependent.updateView function but later you may want to add/remove/change the order of tasks to do after data is fetched. This can all be configured in a app.init function or per procedure in a controller that kicks of certain procedures (like log in, search, ...).
Instead of creating a whole bunch of specific functions in Ajax (fetchUserPrefs, login, search, ...) you can create one general function and have the controller add listeners or pass the next event when fetchData is complete to run the correct next function.
Here is some pseudo code:
var app = {
init:function(){
mediator.add("updateLogin",domDependent.updateView);
mediator.add("updateLogin",app.loadUserPrefs);
mediator.add("failLogin",domDependent.updateView);
},
login: function(){
mediator.trigger("loadingSometing",{type:"login"});
ajax.fetch({
onComplete:"updateLogin",//what listens to updateLogin you decided in init
onFail:"failLogin",
loginDetails:domDependent.getLogin(),
url:settings.loginUrl,
type:"post"
});
}
}
var ajax = {
fetch:function(data){
data = data || {};
//simple check for onComplete, it's mandatory
var complete = data.onComplete || app.raiseError("ajax.fetch needs onComplete");
//other code to validate data and making ajax request
onSuccess:function(resp){
//mutate data object as the mediator will pass it to
// whatever other function is called next
// you don't hard code domDependent.updateView and
// app.loadUserPrefs because fetch can be used generally and
// success may have to do completely different things after its done
// and you want to define procedures in init, not all over your code
data.response=resp;
//trigger event to do whatever needs to be done next
mediator.trigger(complete,data);
}
}
}
As you can see it gets complicated and maybe doesn't look like code you're used to but it's highly configurable.
I may have misunderstood the advantages of the mediator pattern to loose couple and if so please comment. I use it to:
Make methods more general instead of copying a lot of logic only
because what to do after it's done is different. In fetch the ajax
object just fetches, this would be the same for login or getting
user preferences, the only thing different is what function to call
next/on error when it's done.
A procedure like login involves multiple functions in multiple
objects if this function chain hard code what to do next once a
particular function is done your procedure of login is defined all
over your code. When defining it in init/config you can easily change the
order or add/remove functions in the chain.
I'm working on a large AngularJS app in which I am trying to encapsulate all my Ajax code into various services which the controllers get data from. The problem revolves around needing to know the status of any ajax calls and displaying the correct information to the user. There could be no data found, data currently loading, or an error that has occurred preventing data from being loaded. The user needs to be shown a loading message, a "no data found" message, or an error message.
Let's say I have a ProjectService. Ideally if there was a method called getAllProjects it would return an array of projects. But that way I have no idea what is happening with the server communication.
So how to I let the controller know if data is loaded, loading, or an error has occurred? The best way I can come up with is using callbacks like in the pseudo code below. Is there any better way to accomplish such a thing or anything I may be overlooking?
Thanks.
app.controller( "ProjectController", function( $scope, ProjectService ){
// Set the initial / default status
$scope.loadStatus = "loading";
// Return an empty array initially that will be filled with
// any data that is returned from the server
// The callback function will be executed when the ajax call is finished
$scope.projects = ProjectService.getProjects(function( status ){
// Alert the controller of a status change
setStatus( status );
});
function setStatus( ){
$scope.loadStatus = status;
// ... update the view or whatever is needed when the status changes....
}
});
app.service( "ProjectService", function( $resource ){
return {
getAllProjects: function(){
// ... load and return the data from the server ...
}
};
});
In our codebase we've just been doing
$scope.flags.loading = true;
$http(...).success(function(){
$scope.flags.loading = false;
});
Yes, this is sort of simplistic, but not all queries require a loading overlay (such as during pagination or refreshing). This is why we have opted not to simply use a decorator.
However, lets say you want to, I can think of a few ways of doing this. Lets say you're like us and keep your flags together in an object. Then you can use associations to your advantage:
MyService.flags = $scope.flags
... (inside the service) ...
this.flags.loading = true/false;
By establishing a reference as a property of the service, you can do all the state toggling from within the service, and avoid cluttering your controller. Again though, this might create the possible drawback of having 2 or more close-together queries conflicting (first query finishes and removes the loading state before the second one completes).
For this reason we have been find with setting the flag. We don't really check for 'loaded' we just check for data or use success callbacks.