I have one variable say var tree.I want to use this variable in two files say a.js and b.js.Both files changes state of variable tree.I want to access that variable in other files with change state.How it is possible??
There are more elegant ways of doing it, as described in the question linked in the comments, but the simplest way is to define a RequireJS module with an object literal to hold the shared state:
define('sharedstuff', [], {tree: "original value"});
And then from other module you can require it:
require(['sharedstuff'], function(sharedstuff) {
sharedstuff.tree = "new value";
};
And if from yet another module you require it, RequireJS will not reload a fresh copy but will instead give you the already loaded version with your shared value populated:
require(['sharedstuff'], function(sharedstuff) {
console.log(sharedstuff.tree) // should be "new value"
};
Related
I couldn't find an answer or a solution to a challenge yet: How can I bind a variable (Session variable, no mongo collection) reactively in angular-meteor?
I'm converting from standalone meteor. Here I could use the template.helper method. As I can't use templates (and iron:router) anymore with angular-meteor and angularui-router, I can't bind reactivity to the helper anymore (at least in my understanding).
I tried this in an meteor-angular controller, which belongs to a sentence.tpl file:
$scope.parsestring = function(input_string){
tokenizer(input_string);
};
$scope.sentence_type = Session.getJSON("current_sentence.sentence_type");
Tokenizing works (I can see it in the debugger), but the value is only displayed, when I reload the page. What I want to achieve is tokenizing a string from an input field into a JSON representation (the tokenizer takes care of that) and displaying it similtaniously from the JSON representation in a structured way (separate html input elements, which are created dynamically). sentence_type is the variable that should be used on the html-page to show and change the sentence type, which can change while typing.
Anybody has some hints? Maybe, I could also use some Angular feature that I don't know?
Cheers,
Jan
Code repo:
My current code looks like this:
My code looks similar to this:
angular.module('ngaignt').controller("InteractorCtrl", ['$scope', '$meteor', '$meteorCollection',
function ($scope, $meteor, $meteorCollection) {
// Autorun is necessary to make reactive variables out of the JSON returns
var c = Tracker.autorun(function (comp) {
$scope.verb_type = Session.getJSON("current_verb.type");
$scope.object_type = Session.getJSON("current_object.type");
$scope.verb_attributes = _.toArray(Session.getJSON("current_verb.attributes"));
$scope.object_attributes = _.toArray(Session.getJSON("current_object.attributes"));
if (!comp.firstRun) {
// only do not do aply at first run becaulse then apply is already running.
$scope.$apply();
}
});
$scope.parsestring = function (input_string) {
interactor(input_string);
};
//$scope.on('$destroy', function () {c.stop()});
}]);
To use reactive variables, you need a reactive computation. You may need to use Tracker.autorun:
$scope.parsestring = Tracker.autorun(function(someStringInSession){
tokenizer(Session.get(someStringInSession));
});
Or you can use Tracker.autorun(func) wherever you use a reactive variable to reactively rerun a function when the variable changes.
good question and the best answer depend on your needs.
There are 2 possible solutions:
If you want to bind a Session variable to a scope variable, use the $meteorSession service.
What it does is that every time the scope variable will change, it will change to Session variable (and trigger an autorun if it's placed inside one).
and every time the Session variable will change, the scope variable will change as well (and change the view that it's placed upon).
If you are using the Session variable just to get a variable reactive (meaning trigger an autorun), you should use getReactively . this just returns the already existing scope variable but trigger an autorun every time it changes. a good example of this can be found it our tutorial.
Note: In anyway, when you use Tracker.autorun inside Angular, you need to connect it to a scope. this can be easily done if you replace Tracker.autorun with the $meteorUtils autorun function
Would be great if you could share a repo so that I can look on the broader perspective and could better determine what's the best solution from the two.
Based on another answer about "session" reacitivity, I could solve the problem. Just use the approach described in the link https://stackoverflow.com/a/21046935/4035797. You have to substitute Deps.autorun by Tracker.autorun though as Deps is deprecated and you have to make the scope variables for use in the template reactive (e.g., $scope.sentence_type = Session.getJSON("current_sentence.sentence_type");) and not the tokenizer.
I am trying to have external modules change my $translateProvider.translation on the main module. see this as a "tranlation plugin" for my app.
it seems like changing translations from the $translate service is not possible.
mymodule.service('MyService', function ($translateProvider) {
var lib = function () {
//EDITED FOR BREVITY
this._registerTranslations = function (ctrl) {
if (!ctrl.i18n) return;
for (var name in ctrl.i18n) {
/////////////////////////////
// THIS IS THE PLACE, OBVIOUSLY PROVIDER IS NOT AVAILABLE!!!!
$translateProvider.translations(name, ctrl.i18n[name]);
//////////////////////////////
}
};
//EDITED FOR BREVITY
};
return new lib();
});
anyone with a bright idea?
So, to answer your question: there's no way to extend existing translations during runtime with $translate service without using asynchronous loading. I wonder why you want to do that anyway, because adding translations in such a way means that they are already there (otherwise you would obviously use asynchronous loading).
Have a look at the Asynchronous loading page. You can create a factory that will load a translation from wherever you want.
I created an Angular constant to hold new translations. If I want to add a new translation, I add it to the constant. Then in my custom loader, I first check the constant to see if the translation exists (either a new one, or an updated one). If so, I load it from the constant. If not, I load it from a .json file (or wherever you load your initial translations from). Use $translate.refresh() to force translations to be reloaded and reevaluated.
Demo here
The demo is pretty simple. You would need to do a little more work if you wanted to just change a subset of the translations, but you get the general idea.
From the AngularJS docs (https://docs.angularjs.org/guide/providers):
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Providers are to be used with the application's .config function. $translateProvider for configuration, $translate for other services and controllers.
I'm currently in the progress of learning Backbone.js and I'm using the book Developping Backbone Applications.
I have a questions about the reference to HTML elements and how they are stored. For example:
initialize: function() {
this.$input = this.$('#new-todo');
Here the HTML element with ID to-do is stored in the this.$input, why do we use the $ in front of input, is this merely a convention? If I change this.$input to this.input my code works fine. I find this confusing because the book states:
The view.$el property is equivalent to $(view.el) and view.$(selector) is equivalent to $(view.el).find(selector).
I would think that $(view.el) does something completely different than (view.el).
How is this.$input saved in Backbone.js? If I console.log it, it produces:
Object[input#new-todo property value = "" attribute value = "null"]
Could someone give me some insight? :)
Using $ infront of a variable name is just a naming convention. It helps developer in distinguishing variable holding jQuery objects from others.
view.$el is a helper variable provided by Backbone, so that we can use it directly, instead of explicitly forming the jQuery object. Hence view.$el is equivalent to $(view.el).
view.$el is assigned in setElement method:
setElement: function(element, delegate) {
// Some code
this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
// Some code
}
Backbone.$ is reference to $ global variable exported by jQuery.
view.$(selector) is a method defined in View. It's definition does exactly same as $(view.el).find(selector)
$: function(selector) {
return this.$el.find(selector);
}
Recall the method signature for angular.module. If the second parameter, requires is provided, then we are creating a new module instead of retrieving an existing one. From all the documentation and examples I've seen, this parameter is always passed an empty array when used. My question is, is requires meant to be used for anything else besides telling Angular to create a new module instead of getting an existing one? What would happen if I instead passed it a non-empty array? Are those values used for any other purpose? Links with solutions are much appreciated. Thanks.
requires meaning an array of modules which your module depends.
example:
moduleA.js
var customModule = angular.module ('ModuleA');
// controller, services, factories , etc codes here
app.js (main app)
var app = angular.module ("app", ["ModuleA"]);
if I just use:
angular.module ("app");
It means that i'm just retrieving the module named "app". Which is useable when controllers or directives or factories is defined in a different JS files and you want to configure it to the module "app"
The second parameter is used to define the module's dependencies - i.e., a list of modules (module names, to be precise) that should be already loaded by the injector before the current module is loaded.
And here's how this param (stored in the module's requires property) is used: (injector.js/loadModules()):
var runBlocks = [], moduleFn, invokeQueue, i, ii;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return; // skipping already loaded modules
loadedModules.put(module, true);
if (isString(module)) {
moduleFn = angularModule(module); // prepared module object
runBlocks = runBlocks.concat(loadModules(moduleFn.requires))
.concat(moduleFn._runBlocks);
// ...
}
// ...
}
return runBlocks;
As you see, this property can be used to set up a hierarchy of dependencies as well (when ModuleFoo depends on ModuleBar depending on ModuleBaz).
I am using Backbone/RequireJS to provide my application with modularization and structure. One thing I am coming up against, and would greatly appreciate some advice in this area.
When a user visits the page, the first thing that happens is some JSON that populates a couple of models. I would like these models to be available where-ever I am in the app, as they contain the data and support for the program. Is it permissible to use window.modelName, or do you recommend another/better way of accomplishing this?
Using your suggested solution defies the whole purpose of using AMD in the first place.
Define a module (let's call it globals) as such:
define(function (require) {
var globals = function () {
return {};
};
return globals();
});
Now, when you init you can add values to it:
globals = require('globals');
globals.mymodel = new MyModel();
mymodel.fetch();
Later, and from any other module, you can access your globals module:
globals = require('globals');
console.log(globals.mymodel.get('myattr');