Meteor - 如何在模板的助手和事件之间传递数据? [英] Meteor - How can I pass data between helpers and events for a template?

查看:35
本文介绍了Meteor - 如何在模板的助手和事件之间传递数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Meteor 有点陌生,我遇到的问题是反应性数据——特别是在我需要根据鼠标或键盘事件更改显示的数据的情况下.用普通的 js 方式做这种事情似乎给我带来了流星的麻烦,因为我改变的一切都会不断重新渲染和重置.

I'm a bit new to Meteor and something I'm having trouble with is reactive data -- particularly in instances where I need to change the data shown based on a mouse or keyboard event. Doing this kind of stuff the normal js way seems to give me trouble in meteor since everything I change gets re-rendered and reset constantly.

所以,我想我会看看这是否是我可以使用 Meteor 的 Deps 对象的情况,但是我不太明白.这是我正在使用的代码:

So, I thought I'd see if this would be a case in which I could use Meteor's Deps object, however I can't quite grasp it. Here's 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 = '';
            }
        }
    })


})();

^这似乎是他们在流星文档(http://docs.meteor.com/#deps_dependencyhttp://docs.meteor.com/#deps_dependency) 用于dependency.changed() 和dependency.depend(),但这只是给了我一个无限循环.

^This seemed to be what they were getting at in the meteor documentation (http://docs.meteor.com/#deps_dependency) for dependency.changed() and dependency.depend(), but all this does is give me an infinite loop.

那么我可以修改我声明 deps 的方式来使数据具有反应性吗?有没有更好的方法来完成这一切?

更新:

尽管我对此持怀疑态度,但我一直倾向于尝试以本地化方式使用 Session.set/Session.get.所以,下次我必须这样做时,我就这样做

Although I was skeptical to do so, I've been inclined to try to use Session.set/Session.get in a localized way. So, the next time I have to do this, I'll just do

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

然后只需从与 Template.tenantsBlock 相关的助手和事件映射中访问此变量.这样他们都可以实时访问数据,并且在数据更改时都可以重新运行.这是我将此脚本转换为的内容(对不起,它们都太大了):

and then just access this variable from within helpers and event maps related to Template.tenantsBlock. That way they all have real time access to the data and they all get re-run when the data changes. Here's what I converted this script into (sorry these are both so large):

(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);
    }
})

})();

推荐答案

您必须克服老派的做法:) Meteor 比您想象的要简单得多.一个好的经验法则是,如果您使用 jQuery 来操作任何 DOM 元素,那么您可能做错了.此外,如果您在不使用集合 API 的情况下访问任何数据,您最好有充分的理由这样做.

You'll have to overcome the old-school way of doing it :) Meteor is a lot simpler than you think. A good rule of thumb is that if you're using jQuery to manipulate any DOM elements, you're probably doing it wrong. Additionally, if you're accessing any data without using the collection API, you'd better have good reason to do so.

就您而言,您根本不需要编写任何手动依赖项.大多数 Meteor 应用程序中很少需要手动依赖.

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

您需要做的第一件事是将所有租户放在一个 Meteor.Collection 中,这将使他们更容易使用.

The first thing you need to do is put all your tenants inside a Meteor.Collection, which will make them easier to work with.

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

你的 tenantsBlock 模板应该看起来像这样(以一些不同的 html 元素为模):

Your tenantsBlock template should look something like this (modulo some 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>

Tenants 中的每个文档应如下所示:

Each document in Tenants should look something like the following:

{
    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 would need is just for the selection/deselection, 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);
    }
});

我再次重申,在使用 Meteor 时,永远不要使用 Javascript 进行 DOM 操作.您只需更新您的数据,如果一切都正确完成,您的模板将被动更新.声明数据的外观,然后更改数据并观察其神奇之处.

Once again, I reiterate that you should never be doing DOM manipulations with Javascript when using Meteor. You just update your data and your templates will reactively update if everything is done correctly. Declare how you want your data to look, then change the data and watch the magic.

这篇关于Meteor - 如何在模板的助手和事件之间传递数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆