Meteor: Sharing/Passing Variable Between Controller and Helper (diff files) - javascript

I'm trying to pass a variable that's defined in my local template helper to the template controller (so I can then submit it with the form and insert it to the collection). Can't figure out how to include that variable in the scope of the controller.
This is my Helper (diff file from controller, as i'm using the meteor boilerplate file structure):
Template.addvenue.rendered = function() {
// Call Multiselector
$('#cuisineType').multiselect({
onDropdownHide: function() {
var cuisineTypeEvent = $('.multiselect-container.dropdown-menu > .active').find('input[type="checkbox"]').map(function() { return this.value;});
}
});
What I need to pass to the Controller is "cuisineTypeEvent" (returns an array of strings ['french', 'american']) so I can insert it into the collection.
Controller (part where I need to pass the array (instead of cuisineType):
var params = {
venueAttributes: {
venueType: venueType,
cuisineType: cuisineType,
}
I looked into creating another helper in the same file, but I only found examples where I do that with a variable defined outside of the Template.xx.rendered one. Mine needs to stay within it as it's created by a dropdown box.
Thanks!
Dan.

You can use Meteor Sessions for this.
Session.set("sessionName",value);
In the controller, you can get the same Session variable using :
var data = Session.get("sessionName");

Related

Sails.js how to call functions within a controller

Getting my hand dirty in Sail.js (and node).
Versions
$ sails --version
1.2.4
$ node --version
v12.16.1
My first sails controller (an example) is as follows:
// MyController
// MyController.js
module.exports = {
sum_it: function (a, b) {
return (a + b);
},
minus_it: function (a, b) {
return (a - b);
},
process_it: function (req, res) {
let i = 12;
let j = 4;
do_what = "sum"; //this will be an input extracted from req
if (do_what == "sum") {
let result = this.sum_it(i, j); //"this" doesn't work????
} else {
let result = this.minus_it(i, j); //"this" doesn't work????
}
console.log(result);
return res.send(result);
}
};
My intention is to have few functions defined within that controller itself as they would be ONLY used under this controller. I used this.sum_it(i, j) this.minus_it(i, j) and both of them don't work.
What is the best way to have multiple functions in the controller and call them within that controller file (assuming those functions are too specific to that controller and hence, no need to take them out and put in the other helper files)?
The way you have to think about it is like this: when Sails runs, it compiles all your controllers, services, helpers, etc and sets all the routes using an internal Express application, so, the concept of "this" inside controllers, services, helpers doesn't work.
For this, sails provides you a globally available object: sails. Within that object you can find all your runtime variables, controllers, services, etc.
To get access to your particular controller action within a controller, for Sails 0.12, you can do:
sails.controllers.my.sum_it(1,2)
For Sails 1.x, you can do:
sails.getActions()['my/sum_it'](1,2)
Finally, if you don't need to expose those functions as actions, you can just make them functions anyhwere in the file outside the module.exports, and call them without this.

AngularJS - split controller functions in multiple files

I'm new in AngularJS and I'm doing a refactor of an AngularJS application and I noticed that there is a single controller file with a lot of functions that manipulate and set scope variables.
Following an example:
test.controller('testCtrl', function testCtrl($scope) {
$scope.init_filters = function() {
$scope.filter_1 = [];
$scope.filter_2 = [];
$scope.filter_3 = [];
$scope.filter_4 = [];
$scope.filter_5 = [];
};
$scope.showChanges = function() {
if ($scope.item_list.length > 0) {
$scope.messages = [];
for (var i = 0; i < $scope.item_list.length; i++) {
$scope.messages.push($scope.item_list[i].message);
}
$scope.another_function();
}else{
// other stuff
}
};
//other functions like these
}
So, I would like to split these functions in multiple JS files. I searched about this problem and I found that in a lot of case is used a service. But I think that this is not my case, because I need to working on directly on the controller's scope.
I mean, I don't want a separated function that get as parameters some scope variables and return the variable.
So, what is the best practices for doing something like this? is it possible?
If you want to use multiple files then split the definition to multiple files by passing the scope to another method and then define the rest of methods there.
File1
app.controller('CtrlOne', function($scope){
app.expandControllerCtrlOne($scope);
});
File2
app.expandControllerCtrlOne = function($scope)
{
}
Check this video
As you said the code you found for controller is large one so there are multiple ways in angular js that you can implemented the separation of code.
I will suggest you to go with following approach:
Use service to add those code in it which you need in other places as well and you know that this code does not require scope object..
Use factory to add some Utility kind of functions. The collection of logic which does not require scope object again...
As controller code is too large, I think View/UI of same also being as per wrote...
So for this you can go with creating directives for section in view..
Where-ever you think this peace of view section can be separate and standalone logical functionality that you can move into directive.
There are three ways to create directive with scopes:
A. Shared Scope B. Isolated Scope C: shared and Isolated scope
In this ways may you can at-least make your controller code readable and looks modular.
Let say::
module.controller('longRunController', function() {
#TYPE 1 code
// some code which fetch dat from API
// some code which save variable and objects which can used in another controller or directives
// some code which need to passed to other controller even after route changes
#TYPE 2
// some code which is only related this controller but has some bussiness logic
// some code which is a kind of utility functino
#TYPE 3
// all $scope related variable $watch, $scope and related variables
// some code of perticular section of which VIEW which handle by this controller
});
Consider in above patter your controller code has:
So type 1 code can be moved to Service
type 2 code can be moved to factory
type 3 code can be move to directives
you can pass $scope as a parameter to the external function.
And because you just use the objectreference, all changes you made in your external functions are made on the $scope object from your controller.
test.controller('testCtrl', function testCtrl($scope)
{
showChanges($scope);
});
...
function showChanges(scope)
{
scope.param1 = "Hello World";
}

Inject a variable from Service to html

I am asked to debug some things in an angular JS app, problem is I dont know anything about this framework and I need to get this done.
I need to inject a variable from my service to a html template.
So I thought I will need to get this variable from Controller, which get it from the Service.
For the moment I have this :
controller.js
$scope.fileURL = null;
var fileURL = ItemsService.fileURL;
$scope.fileURL.push(fileURL);
services.js
I declare this inside my service class :
this.fileURL = null;
and i declare it my method this way :
self.fileURL = fileURL;
But I got this error TypeError: Cannot call method 'push' of null
And fileURL is defined and got a value in my method.
Any idea why ?
Thanks
more performant solution
Thanks to maurycy for his comments.
Making your service visible through $scope like this:
$scope.itemService = ItemService;
and using it in your template for example like this:
{{itemService.fileURL}}
will be more perfomant, less complex and have all other advantages as well.
old solution
Why don't you just pass through your variable:
In your service:
this.fileURL = "something";
in your controller:
$scope.fileURL = function() {
return ItemsService.fileURL;
};
This way changes made in your service (like a update of fileURL will trigger an update of the view through the controller.
FYI:
If you define your $scope-variable like this:
Object.defineProperty($scope, 'fileURL', {
get: function() {
return ItemService.fileURL;
},
set: function(newValue) {
ItemService.fileURL = newValue;
}
});
You may also update the variable in the service from the controller AND childscopes will have the same functionality, since upon $scope.fileURL = 'different'; they won't introduce a new property fileURL which hides the original one and doesn't wire to the service anymore.

Edit or Remove BreezeJS EntityManager Once Instance Reference Lost

I'm constructing a CRM application with a SPA structure, using BreezeJS and AngularJS, and I'm utilizing a dynamically-generated tabbed environment to display what I'll refer to here on out as modules. When a user clicks a side menu item, a new tab is created, and an HTML template (aka module) is loaded into the new content area. While some of the module types are to be opened only once at a time (a grid of Accounts), others, such as an Account Editor module, can be opened many times. That way, the user can modify many accounts at any given time throughout the day, but always be doing so from a single Accounts grid instance.
So far, I have a working system for the Account Editor module, in that I create a master Breeze EntityManager with appropriate configuration parameters (service name, save options, etc.) and then make a copy of it any time a new Account Editor is created, using masterManager.createEmptyCopy() (as per the code outlined at http://www.breezejs.com/documentation/multiple-managers#CreateMultipleManagers):
var serviceName = "/breeze/accounts";
var ds = new breeze.DataService({
serviceName: serviceName,
hasServerMetadata: true
});
var masterManager = new breeze.EntityManager({
dataService: ds,
saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false })
});
function createManagerCopy() {
// same configuration as master; no entities in cache.
var sandboxManager = masterManager.createEmptyCopy();
return sandboxManager;
}
Then, I call an EntityQuery, by passing in the copied EntityManager and entity Id (key), in order to get the appropriate Account and populate each open editor with apparently all the benefits of Breeze.
function queryAccountByKey(mgr, key) {
var keyPredicate = breeze.Predicate.create('id', 'eq', key);
var query = new breeze.EntityQuery('AccountsBase')
.expand('ContactsBase')
.where(keyPredicate);
var promise = mgr.executeQuery(query)
.catch(queryFailed);
return promise;
function queryFailed(error) {
console.log('Query Account by Id Failed', error);
return $q.reject(error); // so downstream promise users know it failed
}
}
There does not appear to be any conflict with the other open editors and their respective entity managers, so long I maintain the copied EntityManager in the module's Angular scope. Editing and saving this way is, well…a breeze! :P (sorry)
The problem I’m having is when I switch to another Angular route, such as a login screen, and then come back to the home screen. Due to the complexities of each tabbed module, any Account Editor module I had opened before the routing took place must be reloaded from stored settings (even if the layout is stored in the cache). However, then there are two Breeze entity managers handling that account. The effect is that saving changes for a single Account Editor now commits twice (or however many times you’ve gone away and back from the home layout).
What I’m trying to figure out is how to get access to a specific EntityManager instance, from the client, once I navigate back to the home layout and the original instance reference (in the scope, in my case) is lost. In other words, is there an EntityManager collection that I can query to reuse or delete an instance? If I can grab a manager instance by name or other Id, I can simply reassign it to my scope without removing and recreating it.
In the event that I do need to remove the EntityManager, I can’t find anything anywhere to describe implementing something like a destroy() method…just a clear() method, which only clears the entities and does not remove the EntityManager from the client. Of course, if I'm going about this all wrong, please advise as to a better approach. Hopefully I've explained things clearly enough that someone can lend a possible solution.
SOLUTION
So, thanks to PW Kad's answer, I was able to reuse the entity managers instead of deleting and re-creating them, by adding them to an empty object collection on the $rootScope when they're initialized (still using the createEmptyCopy() method outlined above). This allows for access throughout the Angular app, without polluting the global namespace. I had already implemented a unique ID to be associated with each tab - and thus the modules in the content areas - so I appended that ID to create a name, such as 'EM_' + instanceId, for storage in the $rootScope.entityManagers object. Later, I can retrieve the EntityManager instance in the $rootScope, using this ID, which is found in each Account Editor's Angular Controller.
Here's the new code:
// NEW: Add an 'entityManagers' object to the $rootScope of my main app module
angular.module('app', [])
.run(['$rootScope', function($rootScope) {
$rootScope.entityManagers = {};
$rootScope.entityManagers.count = 0;
}]);
// In the dataServices factory for the main app module
var serviceName = "/breeze/accounts";
var ds = new breeze.DataService({
serviceName: serviceName,
hasServerMetadata: true
});
var masterManager = new breeze.EntityManager({
dataService: ds,
saveOptions: new breeze.SaveOptions({ allowConcurrentSaves: false })
});
function createManager(instanceId) {
// make a copy of the above EntityManager (with no cached entities)
var sandboxManager = masterManager.createEmptyCopy();
// NEW: Save the EntityManager instance to the $rootScope
$rootScope.entityManagers['EM_' + instanceId] = sandboxManager;
$rootScope.entityManagers.count++;
return sandboxManager;
}
// In the event that you want to delete the EntityManager from the $rootScope
function deleteManager(instanceId) {
var manager = $rootScope.entityManagers['EM_' + instanceId];
manager.clear();
delete $rootScope.entityManagers['EM_' + instanceId];
$rootScope.entityManagers.count--;
}
// And lastly, inside any Angular controller
$scope.instanceId = '1234'; // Dynamically-assigned at runtime
$scope.init = function() {
var manager = $rootScope.entityManagers['EM_' + $scope.instanceId];
if (manager === undefined) {
$scope.entityManager =
entityManagerService.createManager($scope.instanceId);
} else {
$scope.entityManager = manager;
}
}
$scope.getEntityById = function(id){
//use $scope.entityManager here to query database via Breeze
}
While I would still like to know where BreezeJS keeps its EntityManager collection, I have a valid solution. I hope it helps someone!
It seems like a poor design choice to reinstantiate a new entity manager every time you change pages as in effect you are losing the caching mechanism and sharing the entities across pages but if you must do so you can always do so fairly trivially with something like -
var manager = {};
manager = manager ? manager.clear() : new breeze.EntityManager();
or
manager = manager ? (function () { delete manager; return new breeze.EntityManager(); })() : new breeze.EntityManager();
or many other ways really.
I would recommend not doing that though and just doing something like this -
var manager = {};
// Some route activation logic
if (!manager) {
manager = new breeze.EntityManager();
}
Edit
Well the short answer is I am not 100% sure how the breeze object in the global namespace is referencing the entity manager. I don't think there is a collection of entity managers that the breeze object keeps, but I may be wrong. I don't see why calling delete on the entity manager isn't working but this should do what you are trying to do -
Somewhere in either one of your closures or in the global namespace create an object called entityManagers. Example -
window.entityManagers = {};
window.entityManagers.count = 0;
Then tack the manager while it is created onto that namespace. There is probably a more dynamic way to do this just giving some pseudo-code -
window.entityManagers.createNewManager = function (name) {
window.entityManagers[name] = new breeze.EntityManager();
}
window.entityManagers.createNewManager('ManagerNumber1');
And then when you want to dispose of a specific instance just clear it then delete it. Get the instance you want either by a variable reference or if you can't do that for some crazy reason just grab it off the affected entity -
window.entityManagers.deleteManager = function (name) {
window.entityManagers[name].clear();
delete window.entityManagers[name];
}
window.entityManagers.deleteManager('ManagerNumber1');
For all intents and purposes, as long as there no other references to that instance of the manager in other modules / controllers / whatever than this should delete the entityManager from the world. I still don't fully understand the use case so take it with a grain of salt.

Using locales options inside the jade filter failed

I'm trying to use locales option inside the filter but faced with problem, that locale-object is not accessible from filter.
Locales:
json
{"title": "HAMPI"}
Filter:
var jade = require(jade);
jade.filters.Posts = function(block) {
return '{block:Posts}'+jade.render(block)+'{/block:Posts}';
};
Input:
body
|#{title}
:Posts
div
a
#{title}
Output:
<body>
HAMPI
{block:Posts}<div><a><undefined></undefined></a></div>{/block:Posts}
</body>
Can I fix or handle this error?
PS You can look at the code in this repository — I'm using grunt and grunt-contrib-jade plugin, but to force grunt-contrib-jade work with filters you should edit ./node_modules/grunt-contrib-jade/tasks/jade.js to reflect changes from this pull request.
Filters are applied at compile time, where as rendering which has access to local variables is done at runtime. So your local variables are not accessible to filters. They only see raw text. So you can do this :
jade.filters.Posts = function(block) {
return '{block:Posts}'+block+'{/block:Posts}'; //remove render
};
This way you will defer rendering of #{title} until you have the variables. It produces this output.
<body>HAMPI{block:Posts}HAMPI{/block:Posts}</body>
How I tested it :
var jade = require(jade);
fn = function(block) {
return '{block:Posts}'+jade.render(block)+'{/block:Posts}';
};
var fn = jade.compile(fs.readFileSync(__dirname + '/file2.jade'));
console.log(fn({"title": "HAMPI"}));
The same issue is mentioned in here: in node.js, how to pass variables to :stylus filter from jade?
For reference you can see these links :
Jade: Pass markdown filter a variable.
:markdown filter processing the text of a String variable
:markdown with variable
[Update]
If you want to use render then why not pass the local vars with it. So if you do :
jade.filters.Posts = function(block) {
return '{block:Posts}'+jade.render(block,{"title": "HAMPI"})+'{/block:Posts}'
};
It gives this:
<body>HAMPI{block:Posts}<div><a><HAMPI></HAMPI></a></div>{/block:Posts}</body>
Downside being your view local cannot be used and you would have to pass it directly.

Categories

Resources