AJAX部件的金字塔及变色龙变色龙、金字塔、部件、AJAX

2023-09-10 13:22:48 作者:ヾ没你我们还会好好

我希望能够轻松地创建Ajax小部件通过变色龙和金字塔在服务器端支持。

确实金字塔提供任何管道code,这将使写小部件容易?

我目前的做法是我有使用home.pt作为渲染一个主视​​图。 home.pt使用一个宏base.pt它定义了页面结构,并提供了一​​个插槽home.pt填补。 base.pt还采用了我写了一个登录窗口小部件的宏(见:account_login_widget.pt下文)。

在理论上,这一切听起来不错...我有一个可重复使用的登录窗口小部件,我可以在很多页面中使用,但我目前的做法并不能很好地工作。我登录的Widget使用像$ {用户名}在其渲染器(该服务器需要定义)变量。我想登录窗体部件和渲染是尽可能独立。但我目前的做事方式,主视图code需要知道的登录窗口小部件的需求,提供用户名,formrender和其他变量的字典。绝对不是好...

我觉得我接近正确的想法,但缺少一些东西...

有什么想法?

base.pt:

 < HTML>
< HEAD>< /头>
<身体GT;
< D​​IV ID =容器>
    < D​​IV ID =头>
        <跨度金属:使用宏=载:account_login_widget.pt>< / SPAN>
    < / DIV>
    < D​​IV ID =中间>
        <跨度金属:定义插槽=内容>< / SPAN>
    < / DIV>
    < D​​IV ID =页脚>< / DIV>
< / DIV>
< /身体GT;
< / HTML>
 
SS系列物料提升机概述及部件优点你知道么

home.pt:

 < D​​IV金属:使用宏=载:base.pt>
<跨度金属:填槽=内容>
    < D​​IV>我的东西< / DIV>
< / SPAN>
< / DIV>
 

account_login_widget.pt:

 <跨度金属:定义宏=account_login_widget>
<脚本类型=文/ JavaScript的>
(函数($){
    $ .fn.my_function =功能(){
        $('#login_form)。递交(函数(五){
            即preventDefault();

            // Ajax调用
            $。员额(some_url,some_data,函数(响应){
                $('#account_login_widget')的HTML(响应);
            });
        };
        回到这一点;
    };
})(jQuery的);

//定义入口点
$(文件)。就绪(函数(){
    $(文件).my_function();
});
< / SCRIPT>

< D​​IV ID =account_login_widget>
< D​​IV ID =login_barTAL:条件=没有用户名>
    $ {form_renderer.begin(...)}
        ......我的形式?
    $ {form_renderer.end()}
    <跨度TAL:条件=login_failed>登录失败< / SPAN>
    < D​​IV ID =forgot_password_link>< A HREF =#>忘记密码< / A>< / DIV>
    < D​​IV ID =create_account_link>< A HREF =$ {SIGNUP_URL}>创建帐户< / A>< / DIV>
< / DIV>
< D​​IV TAL:条件=用户名和GT;
    欢迎<强> $ {用户名}< / STRONG>! &所述; A HREF =$ {logout_url}>注销&所述; / a取代;
< / DIV>
< / DIV>
< / SPAN>
 

解决方案

处理这个问题的一个好方法是将您的account_login_widget有自己的看法,联想这样的:

  @view_config(NAME ='login_widget',
             渲染='模板/ account_login_widget.pt)
高清login_widget(要求):
    返回{用户名:...}
 

您应该然后能够访问的http:// yourapp / login_widget 并取回只小部件的HTML

什么剩下要做的就是调用视图,包括在您的模板生成的HTML。也就是说代替,:

 <跨度金属:使用宏=载:account_login_widget.pt>< / SPAN>
 

你会想是这样的:

 <跨度TAL:更换=结构render_view('login_widget')>< / SPAN>
 

render_view 然而,这并不在模板中存在的;你必须提供它自己。这是最好使用之前渲染事件这样的:http://docs.pylonsproject.org/projects/pyramid/dev/narr/hooks.html#beforerender-event

 从pyramid.events导入用户
从pyramid.events进口BeforeRender
从pyramid.view进口render_view_to_response

@subscriber(BeforeRender)
高清add_render_view_global(事件):
    事件['render_view'] =拉姆达名称:render_view_to_response(背景下,要求名,安全).ubody
 

完成。这种方法也可以帮助你曾经需要(重新)加载部件动态通过AJAX。

I would like to be able to easily create ajax 'widgets' backed by chameleon and pyramid on the server side.

Does Pyramid provide any plumbing code that would make writing widgets easy?

My current approach is I have a home view which uses home.pt as the renderer. home.pt uses a macro base.pt which defines the page structure and provides a slot for home.pt to fill. base.pt also uses a login 'widget' macro that I have written (see: account_login_widget.pt below).

In theory, this all sounds great...I have a reusable login widget that I can use in many pages, but my current approach doesn't work very well. My login widget uses variables like ${username} in its renderer (which the server needs to define). I want the login widget and its rendering to be as independent as possible. But with my current way of doing things, the home view code needs to be aware of the login widget's needs and provide username, formrender and other variables in the dictionary. Definitely not good...

I feel like I'm close to the right idea, but missing some things...

Any thoughts?

base.pt:

<html>
<head></head>
<body>
<div id="container">
    <div id="header">
        <span metal:use-macro="load: account_login_widget.pt"></span>     
    </div>
    <div id="middle">
        <span metal:define-slot="content"></span>
    </div>
    <div id="footer"></div>
</div>
</body>
</html>

home.pt:

<div metal:use-macro="load: base.pt">
<span metal:fill-slot="content">
    <div>my stuff</div>
</span>
</div>

account_login_widget.pt:

<span metal:define-macro="account_login_widget">
<script type="text/javascript">
(function($) {
    $.fn.my_function = function() {
        $('#login_form').submit(function(e) {
            e.preventDefault();

            // ajax call
            $.post(some_url, some_data, function(response) {
                $('#account_login_widget').html(response);
            });
        };
        return this;
    };
})(jQuery);

// Define the entry point    
$(document).ready(function() {
    $(document).my_function();
});
</script>

<div id="account_login_widget">
<div id="login_bar" tal:condition="not username">
    ${form_renderer.begin(...)}
        ... my form ...
    ${form_renderer.end()}
    <span tal:condition="login_failed">Login failed</span>
    <div id="forgot_password_link"><a href="#">Forgot Password?</a></div>
    <div id="create_account_link"><a href="${signup_url}">Create Account</a></div>
</div>
<div tal:condition="username">
    Welcome <strong>${username}</strong>! <a href="${logout_url}">Logout</a>
</div>
</div>
</span>

解决方案

A good way of dealing with this is to associate your account_login_widget with its own view, like:

@view_config(name='login_widget',
             renderer='templates/account_login_widget.pt')
def login_widget(request):
    return {'username': ...}

You should then be able to visit http://yourapp/login_widget and get back only the widget's HTML.

What's left to do is to call the view and include the resulting HTML in your template. That is, instead of:

<span metal:use-macro="load: account_login_widget.pt"></span>

you'll want something like:

<span tal:replace="structure render_view('login_widget')"></span>

render_view however doesn't exist in templates; you'll have to provide it yourself. It's best to use the Before Render Event for this: http://docs.pylonsproject.org/projects/pyramid/dev/narr/hooks.html#beforerender-event

from pyramid.events import subscriber
from pyramid.events import BeforeRender
from pyramid.view import render_view_to_response

@subscriber(BeforeRender)
def add_render_view_global(event):
    event['render_view'] = lambda name: render_view_to_response(context, request, name, secure).ubody

Done. This approach will also help should you ever need to (re)load widgets dynamically through AJAX.