问题描述
我正在做一个使用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模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!