本文介绍了在Knockout attr绑定下使用Jinja2模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个使用Flask和Knockoutjs的项目。我正在使用Knockout来显示评论,并且下面的评论者的名字也会被显示出来,当点击的时候把这个人带到那个用户的个人资料里



这里是代码



$ p $ < a data-bind =attr:{href:'{{url_for('user_profile')}}'+'/' name()+'/'+ uid()+'/'}>< p data-bind =text:name>< / p>< / a>

但是在上面的代码中出现了一个Jinja2模板错误:

  BuildError:('user_profile',{},None)

所以我改了上面这段代码,提到了knockout attr文档

 < a data-bind =attr:{href:'{{url_for('user_profile')} }',name:name,uid:uid}>< p data-bind =text:name>< / p>< / a> 

但是同样的错误是

<$ p $ ('user_profile',{},None)

意味着user_profile视图没有获得所需的变量。在淘汰赛中,做到这一点的方式是attr绑定。我已经提到这个问题




但是没有按预期工作

解决方案

您不显示 user_profile 端点的定义,但是我敢打赌,这或多或少是这样的:

  @ app.route('/ user /< name> /< uid>)
def user_profile(name, uid):
$ ...

你得到的Jinja2错误是因为你的 user_profile 端点需要两个参数,而不是给$ url_for()



这里的问题是 url_for()会在服务器中生成URL,但是您需要Knockout在客户端生成的URL。你在一个解决方案的尝试是混合双方,但 url_for()不能使用部分信息,你必须给它整个事情。



我可以为这个问题想两个可能的解决方案。第一个是我认为最好的一个,第二个更接近你迄今为止所做的。

解决方案#1



做淘汰赛的方式。 Knockout控制的按钮或链接中的点击应由Knockout控制器处理。所以你可以把< a> 标签写成这种样式:

 < a data-bind =click:$ parent.showProfileclass =btn>< p data-bind =text:name>< / a> 

然后你的Knockout控制器将有一个 showProfile()
$ b

  self.showProfile = function(user){
window.location = user.profileUrl

code $


为了达到这个目的,你需要添加一个 profileUrl 键到Flask返回到Knockout应用程序的JSON字典。你不会显示你的应用程序的这部分,我想这应该很容易添加,因为现在的URL完全在服务器中生成,你可以自由使用 url_for()并提供所有的参数。

解决方案#2



如果您想修正显示的代码那么你不得不放弃使用 url_for()并在客户端完全构建URL。我认为下面的例子应该工作得很好:

 < a data-bind =attr:{href:'/ user /'+ name()+'/'+ uid()+'/'}>< p data-bind =text:name>< / p>< / a> 

如果您不想放弃 url_for()完成,那么你必须创建一个不需要附加参数的路由,以便至少从服务器获得基本URL:



<$ p $ ('/ user /< name> /< uid>')
def user_profile(name = None,uid = None):
如果name是None或uid是None:
abort(400)#bad request
#...

现在您可以说 url_for('user_profile'),您将返回 / user ,你可以在Javascript中追加剩余的参数。在烧瓶方面,我相信你的第一个例子应该工作。

作为一个侧面说明,我希望你知道,当点击链接将吹走你的Knockout应用程序,将被替换为一个新的页面(当然可能有另一个Knockout应用程序的实例)。另一个选择是使用一个单页面的应用程序,那么对用户配置文件的改变完全发生在Javascript方面。但是,这当然会把更多的应用移到客户端。



我希望这有助于!


I am making a project using Flask and Knockoutjs. I am using Knockout to show comments and below the commentor's name would also be displayed which is when clicked takes the person to that user profile

Here is the code

<a data-bind="attr: { href: '{{ url_for('user_profile')}}' + '/' + name() + '/' + uid() + '/'  }"><p data-bind="text: name"></p></a>

but in the above code there comes a Jinja2 Template error as

BuildError: ('user_profile', {}, None)

So I changed the above piece of code referred knockout attr documentation Knockout attr binding

<a data-bind="attr: { href: '{{ url_for('user_profile')}}', name: name , uid: uid  }"><p data-bind="text: name"></p></a>

but the same error as

BuildError: ('user_profile', {}, None)

It means that user_profile view is not getting the required variables. In knockout the way to do this is attr binding. I have referred this question

Jinja2: Flask's url_for() combined with Knockout's attr binding

But nothing working as expected

解决方案

You don't show the definition of your user_profile endpoint, but I bet it is more or less like this:

@app.route('/user/<name>/<uid>')
def user_profile(name, uid):
    # ...

The Jinja2 error that you get occurs because your user_profile endpoint requires two arguments that you are not giving to url_for().

The problem here is that url_for() generates URLs in the server, but you need the URLs generated in the client by Knockout instead. Your attempt at a solution is mixing both sides, but url_for() cannot work with partial information, you have to give it the whole thing.

I can think of two possible solutions for this problem. The first is the one I consider best, the second is closer to what you have done so far.

Solution #1

Do it the Knockout way. A click in a button or link controlled by Knockout should be handled by a Knockout controller. So you would write that <a> tag as something of this style:

<a data-bind="click: $parent.showProfile" class="btn"><p data-bind="text: name"></a>

Then your Knockout controller will have a showProfile() method that will issue the redirect:

self.showProfile = function(user) {
    window.location = user.profileUrl
}

For this to work you need to add a profileUrl key to the JSON dictionary that Flask returns to the Knockout app. You don't show this part of your application, I imagine this should be easy to add, and since now the URLs are generated entirely in the server you are free to use url_for() and provide all the arguments.

Solution #2

If you prefer to fix the code you show above, then you have to give up the use of url_for() and build the URLs entirely in the client. I think the following example should work just fine:

<a data-bind="attr: { href: '/user/' + name() + '/' + uid() + '/'  }"><p data-bind="text: name"></p></a>

If you don't want to give up url_for() completely, then you have to create a route that does not need the additional arguments, so that at least you get the base URL from the server:

@app.route('/user')
@app.route('/user/<name>/<uid>')
def user_profile(name = None, uid = None):
    if name is None or uid is None:
        abort(400) # bad request
    # ...

Now you can say url_for('user_profile') and you will get back /user, to which you can append the remaining arguments in Javascript. With this change in the Flask side I believe your first example should work.

As a side note, I hope you are aware that when the link is clicked that will blow away your Knockout app, which will be replaced with a new page (that may have another instance of the Knockout app, of course). Another option would be to use a single-page app, so then the change to the user profile happens entirely in the Javascript side. But of course this will move more of your app into the client.

I hope this helps!

这篇关于在Knockout attr绑定下使用Jinja2模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-28 22:44