Open joaoventura opened 10 years ago
You have to translate heavy_clientside_computation
like this:
class HellowWorldApp:
def initialize(self, **kwargs):
self.rdoc = kwargs['remote_document']
self.rdoc.body.element(h1='Hello World!!!').events.add(click=self.clicked, translate=True)
self.rdoc.translate(self.heavy_clientside_computation)
def clicked(self):
heavy_clientside_computation()
def heavy_clientside_computation(self):
# Do something heavy on the client's browser
see below the hello world example, I modified it so every click on the h1 also prints to the console. I've tested it works as expected:
from webalchemy import server
class HellowWorldApp:
def initialize(self, **kwargs):
self.rdoc = kwargs['remote_document']
self.rdoc.translate(self.print_something)
self.rdoc.body.element(h1='Hello World!!!').events.add(click=self.clicked, translate=True)
self.rdoc.body.element(h2='--------------')
self.rdoc.stylesheet.rule('h1').style(
color='#FF0000',
marginLeft='75px',
marginTop='75px',
background='#00FF00'
)
def print_something(self):
print('hi there!')
def clicked(self):
self.textContent = self.textContent[1:]
rpc(self.handle_click_on_backend, 'some message', 'just so you see how to pass paramaters')
print_something()
def handle_click_on_backend(self, sender_id, m1, m2):
self.rdoc.body.element(h1=m1+m2)
if __name__ == '__main__':
# this import is necessary because of the live editing. Everything else works OK without it
from hello_world_example import HellowWorldApp
server.run(HellowWorldApp)
I think the decorator is a good idea but I need to think how this could be implemented, since currently it needs the runtime remote-document obejct to work...
EDIT: no self.
needed to call heavy_clientside_computation
I also saw that "problem" with the remote-document object. The only solution I could find so far was to make a base class for the framework (something like WebAlchemyApp - which everyone's apps would inherit from), and make the remote-document a property of that base class. Then, the decorator would only be a wrapper to "self.rdoc.translate(func)"..
What do you think? Any drawbacks by having a WebAlchemyApp Base Class? This would allow to simplify things such as this one..
I'm not sure how this would work... Decorating happens at "compile" time right? I'm ok with having to inherit, could you open a pull request on a different branch so I can test, Or just put the needed code in this thread? Otherwise you'll have to explain in greater detail how it will work so I'll understand and implement
Thanks!
Maybe one way to make this work is having a decorator that just "marks" which functions should be translated. Then when the app is created the server could scan the app and translate the required functions
I'm also not very used to decorators, but I'll try to get something to work.
Your second idea (translation on-the-fly) is also good since it would allow to do another thing that I was going to suggest later: Apply the same thing (remotemethods vs local methods) on generic classes. This could be useful for API's where you would like much of the code of a class to be executed on the client, and some code on the server (things like DB accesses).
Things like the following would be great to do transparently:
class SomeAPI:
def db(client, op):
""" This opens a connection on the local drive and executes an operation. """"
conn = open_connection("home/user/path/somedb.db")
if (op == "save"):
conn.save(client)
elif ......
@remotemethod
def saveClient(self, client):
self.db(client, "save")
The remote method would "see" that the function "db" was not local, and would in the background do an RPC call to execute it on server...
To put code on the client allows us, developers, to have less server requirements, that is, we can use cheaper servers.. :)
Just a small note: I think a better name for the decorator would be @clientside.
remote method is an unclear name, If you have server centric point of view you would read remote as client side and if you have browser centric point of view you would read remote as server side.
On Wednesday, January 29, 2014, João Ventura notifications@github.com wrote:
I'm also not very used to decorators, but I'll try to get something to work.
Your second idea (translation on-the-fly) is also good since it would allow to do another thing that I was going to suggest later: Apply the same thing (remotemethods vs local methods) on generic classes. This could be useful for API's where you would like much of the code of a class to be executed on the client, and some code on the server (things like DB accesses).
Things like the following would be great to do transparently:
class SomeAPI:
def db(client, op): """ This opens a connection on the local drive and executes an operation. """" conn = open_connection("home/user/path/somedb.db") if (op == "save"): conn.save(client) elif ...... @remotemethod def saveClient(self, client): self.db(client, "save")
The remote method would "see" that the function "db" was not local, and would in the background do an RPC call to execute it on server...
To put code on the client allows us, developers, to have less server requirements, that is, we can use cheaper servers.. :)
Reply to this email directly or view it on GitHubhttps://github.com/skariel/webalchemy/issues/140#issuecomment-33619111 .
just tried so close this issue, but everything I try has some major downside. For now I think it's better to just continue with what we have.
Also- the way I showed above for translation is dangerous. It can create namespace problems. For e.g. when using translate('print_hi')
it will create a function named print_hi in the global js namespace. Imagine you translate click
- you would have 10 versions.
The solution is to use self.print_hi = translate('self.print_hi')
and then call this function from JS with srv: srv(self.print_hi)()
. This works since the proxy has a mangled name, and the srv escapes that name.
So the correct hello world above should look like:
from webalchemy import server
from webalchemy.remotedocument import rpc, srv
class HellowWorldApp:
def initialize(self, **kwargs):
self.rdoc = kwargs['remote_document']
self.print_hi = self.rdoc.translate(self.print_hi)
self.rdoc.body.element(h1='Hello World!').events.add(click=self.clicked, translate=True)
self.rdoc.body.element(h2='--------------')
self.rdoc.stylesheet.rule('h1').style(
color='#FF0000',
marginLeft='75px',
marginTop='75px',
background='#00FF00'
)
def clicked(self):
self.textContent = self.textContent[1:]
rpc(self.handle_click_on_backend, 'some message', 'just so you see how to pass paramaters')
srv(self.print_hi)()
def print_hi(self):
print('hi!')
def handle_click_on_backend(self, sender_id, m1, m2):
self.rdoc.body.element(h1=m1+m2)
This version works, I just tested. (note the imported srv and rpc functions above are just empty methods so the IDE doesn;t complain, I still haven't syncd this with github...)
Suppose I want to implement a function on the client side, which is not specifically triggered by an event. Something like this:
So, by clicking on "Hello World" the "clicked" event is fired, but then the browser throws a JS Error because "heavy_clientside_computation(self)" was not compiled to Javascript and sent to the client..
Is there a solution for this now as the framework is?
If not, may I suggest something like a decorator so the framework knows which functions are to be sent to the client? It could be something like the following, and it could be applied to all "remote" methods, including those triggered by events (as python zen's explicit is better than implicit):
In this case, all function calls inside @remotemethod's would be local browser calls, unless there was the rpc() call, which would be targeting the server.