Meteor - How to transfer data between helpers and events for a template?

I'm a little new to Meteor, and I'm having problems with reactive data - especially when I need to change the data presented on the basis of the mouse or keyboard events. Doing this kind of thing in the usual js way seems to be causing me meteor problems because everything I change is constantly being updated and reset.

So, I thought I'd see if this would be the case when I can use the Meteor Deps object, but I cannot fully understand it. Here is the code I'm using:

(function(){ var tenants = []; var selectedTenant = 0; var tenantsDep = new Deps.Dependency; Template.tenantsBlock.tenantsList = function() { tenants = []; var property = $properties.findOne({userId: Meteor.userId(), propertyId: Session.get('property')}); var tenancies = _Utils.resolveTenancies(property, true, null, true); for(var i = 0; i < tenancies.length; i++) { if(tenancies[i].tenancyId == Session.get('tenancy')) { tenants = tenants.concat(tenancies[i].otherTenants, tenancies[i].primaryTenant); } } tenants[selectedTenant].selected = 'Selected'; tenantsDep.changed(); return tenants; }; Template.tenantsBlock.onlyOneTenant = function() { tenantsDep.depend(); return tenants.length > 1 ? '' : 'OneChild'; }; Template.tenantsBlock.phoneNumber = function() { tenantsDep.depend(); for(var i = 0; i < tenants[selectedTenant].details.length; i++) if(_Utils.getDynamicContactIconClass(tenants[selectedTenant].details[i].key) == 'Phone') return tenants[selectedTenant].details[i].value; return null; }; Template.tenantsBlock.emailAddress = function() { tenantsDep.depend(); for(var i = 0; i < tenants[selectedTenant].details.length; i++) if(_Utils.getDynamicContactIconClass(tenants[selectedTenant].details[i].key) == 'Email') return tenants[selectedTenant].details[i].value; return null; }; Template.tenantsBlock.addedDate = function() { tenantsDep.depend(); return _Utils.timeToDateString(tenants[selectedTenant].created); }; Template.tenantsBlock.events({ 'click .Name': function(e, template) { tenantsDep.depend(); var _this = e.currentTarget; var tenantName = _this.innerHTML; $(_this).addClass('Selected'); $(_this).siblings().removeClass('Selected'); for(var i = 0; i < tenants.length; i++) { if(tenants[i].name == tenantName) tenants[i].selected = "Selected"; else tenants[i].selected = ''; } } }) })(); 

^ It seems like this is what they got in the meteor documentation ( http://docs.meteor.com/#deps_dependency ) for dependency.changed () and dependency.depend (), but all this gives me an infinite loop.

Can I change the way deps are declared to make this data reactive? Is there a better way to do this all together?

UPDATE:

Although I was skeptical about this, I was inclined to try to use Session.set / Session.get in a localized way. So next time I do it, I just do

 Session.set('tenantsBlock' {tenants: [], selectedTenant: 0}); 

and then just access this variable from the helpers and event cards associated with Template.tenantsBlock. Thus, everyone has access to data in real time, and they all start again when the data changes. Here I turned this script into (sorry, both of them are so big):

 (function() { Template.tenantsBlock.created = Template.tenantsBlock.destroyed =function() { _Utils.setSession('tenantsBlock', { tenants: [], selectedTenant: 0 }) }; Template.tenantsBlock.tenantsList = function() { var localContext = Session.get('tenantsBlock'); localContext.tenants = []; var property = $properties.findOne({userId: Meteor.userId(), propertyId: Session.get('property')}); var tenancies = _Utils.resolveTenancies(property, true, null, true); for(var i = 0; i < tenancies.length; i++) { if(tenancies[i].tenancyId == Session.get('tenancy')) { localContext.tenants = localContext.tenants.concat(tenancies[i].otherTenants, tenancies[i].primaryTenant); break; } } localContext.tenants[localContext.selectedTenant].selected = 'Selected'; Session.set('tenantsBlock', localContext); return localContext.tenants; }; Template.tenantsBlock.onlyOneTenant = function() { var localContext = Session.get('tenantsBlock'); return localContext.tenants.length > 1 ? '' : 'OneChild'; }; Template.tenantsBlock.phoneNumber = function() { var localContext = Session.get('tenantsBlock'); for(var i = 0; i < localContext.tenants[localContext.selectedTenant].details.length; i++) if(_Utils.getDynamicContactIconClass(localContext.tenants[localContext.selectedTenant].details[i].key) == 'Phone') return localContext.tenants[localContext.selectedTenant].details[i].value; return null; }; Template.tenantsBlock.emailAddress = function() { var localContext = Session.get('tenantsBlock'); var selectedTenantDetails = localContext.tenants[localContext.selectedTenant].details; for(var i = 0; i < selectedTenantDetails.length; i++) if(_Utils.getDynamicContactIconClass(selectedTenantDetails[i].key) == 'Mail') return selectedTenantDetails[i].value; return null; }; Template.tenantsBlock.addedDate = function() { var localContext = Session.get('tenantsBlock'); return _Utils.timeToDateString(localContext.tenants[localContext.selectedTenant].created); }; Template.tenantsBlock.events({ 'click .Name': function(e, template) { var localContext = Session.get('tenantsBlock'); var _this = e.currentTarget; var tenantName = _this.innerHTML; for(var i = 0; i < localContext.tenants.length; i++) { if(localContext.tenants[i].name == tenantName) { localContext.tenants[i].selected = 'Selected'; localContext.selectedTenant = i; } else { localContext.tenants[i].selected = ''; } } Session.set('tenantsBlock', localContext); } }) })(); 
+6
source share
2 answers

You will have to overcome the old school to do this. A meteor is much simpler than you think. A good rule of thumb is that if you use jQuery to control any DOM elements, you are probably mistaken. In addition, if you access any data without using the collection API, you I have every reason for this.

In your case, you don’t need to specify any manual dependencies at all. Manual dependencies are rarely needed in most Meteor applications.

The first thing you need to do is place all of your tenants inside Meteor.Collection , which will facilitate their work.

 Tenants = new Meteor.Collection("tenants"); 

Your tenantsBlock template should look something like this (modulo several different html elements):

 <template name="tenantsBlock"> <ol> {{#each tenants}} <li class="name {{selected}}"> <span>Primary Tenant: {{primaryTenant}}</span> <span>Other Tenants: {{otherTenants}}</span> <span>Phone Number: {{phoneNumber}}</span> <span>Email Address: {{emailAddress}}</span> <span>Added Date: {{addedDate}}</span> </li> {{/each}} </ol> </template> 

Each document in Tenants should look something like this:

 { primaryTenant: "Joe Blow", otherTenants: "Mickey Mouse, Minnie Mouse", phoneNumber: "555-234-5623", emailAddress: " joe.blow@foo.com ", addedDate: "2005-10-30T10:45Z" } 

Then all the code you need is just for select / select, and you can delete everything else:

 Template.tenantsBlock.tenants = function() { return Tenants.find(); }; Template.tenantsBlock.selected = function() { return Session.equals("selectedTenant", this._id); }; Template.tenantsBlock.events({ 'click .name': function(e) { Session.set("selectedTenant", this._id); } }); 

Once again, I repeat that you should never manipulate the DOM with Javascript when using Meteor. You simply update your data and your templates will be actively updated if everything is done correctly. Announce how your data will look, and then modify the data and watch the magic.

+15
source

The meteor has really evolved since I published it back in 2013. I thought I should post a modern, excellent method.

For a while, you can now create ReactiveVar , and now you can attach them directly to the templates. ReactiveVar, similar to a session, is a repository of reactive data. However, ReactiveVar contains only one value (of any type).

You can add ReactiveVar to the client side of your project by running this in your terminal from the application root directory:

$ meteor add reactive-var

This javascript shows how you can pass a variable between the onCreated , onRendered , onDestroyed , events and helpers .

 Template.myTemplate.onCreated = function() { // Appends a reactive variable to the template instance this.reactiveData = new ReactiveVar('Default Value'); }; Template.myTemplate.events({ 'click .someButton': (e, template) => { // Changes the value of the reactive variable for only this template instance template.reactiveData.set('New Value'); }, }); Template.myTemplate.helpers({ theData: () => { // Automatically updates view when reactive variable changes return Template.instance().reactiveData.get(); }, }); 

This is excellent for several reasons:

  • It binds a variable to only one instance of the template. Especially useful in cases where you can have a dozen instances of the template on the page, which requires independent states.
  • It disappears when the pattern leaves. Using ReactiveVar or Session variables, you will need to clear the variable when the template is destroyed (even if it is destroyed predictably).
  • This is just clean code.

Bonus points: see ReactiveDict for cases when you have many instances of the template on the page at the same time, but you need to manage several reactive variables, and these variables are saved during the session.

0
source

Source: https://habr.com/ru/post/954093/


All Articles