How to create your first "input" component
I assume that you have the minimal bases (html's crafting and events bindings). And I will show you how to create an "reactive" input field .... it's, by far, the most complex thing ;-). But it's a component which cover well all the core features of htag concepts. If you understand that : you can start to craft your own/complex components easily.
Let's create a minimal htag app, which is runn'able as is (if you got the dependencies for the DevApp runner):
from htag import Tag
###############################################################################
# the app side
###############################################################################
class Test(Tag.body):
def init(self):
self <= "here, we want an input'able"
###############################################################################
# the runner side
###############################################################################
if __name__=="__main__":
from htag.runners import Runner
Runner(Test).run()
Now, we want to create an input field. In the htag style, you will
create something like that (replace your Test
class):
Now, we've got an input field with a default value. Changing it, on UI side, does nothing.
Let's change that (replace your Test
class):
class Test(Tag.body):
def init(self):
self <= Tag.input(_value="default", _onchange = self.myonchange)
def myonchange(self,o):
print("it has changed")
Now, changing it on UI side notify the python side, that something has changed !
The callback myonchange
receive the object which has fired the event (o).
But the input field has not sent its new content !
Let's change that (replace your Test
class):
class Test(Tag.body):
def init(self):
self <= Tag.input(_value="default", _onchange = self.bind( self.myonchange, b"this.value" ) )
def myonchange(self,value:str):
print("it has changed ->",value)
Assigning _onchange = self.myonchange
is strictly the same as _onchange = self.bind( self.myonchange )
.
But the form self.bind( <method>, ....)
is better when you need to send arguments. In this case, it will send the client value
to the myonchange
callback (using the b"trick"
to get data from client/js side).
It's better, but it will be a lot better to make it a "htag component", to be re-usable in another htag apps.
Let's create a MyInput component
, and reuse it from the main class Test
like that:
class MyInput(Tag.input):
def init(self,value=""):
self.value = value # store the real value in a property value
self["value"]=self.value # set the @value attrib of html'input
self["onchange"] = self.bind( self._set, b"this.value" ) # assign an event to reflect change
def _set(self,value:str): # when changed, keep the property value up-to-date
self.value=value
class Test(Tag.body):
def init(self):
self <= MyInput("default")
Now, when you change the content of your MyInput
... the change is reflected on python side !
And you can rebind its onchange event, to get the changed value ....(replace your Test
class)
class Test(Tag.body):
def init(self):
self.myinput = MyInput("default")
self.myinput["onchange"].bind( self.changed )
#construct the layout
self <= self.myinput
def changed(self,o):
print("Changed ->",o.value) # o is the object which has fired the event
print("Changed ->",self.myinput.value) # or access direct to your reference
If you understand all that concepts ^^, you can start to build your own/complex components.
Here is a login form, using our newly widget (replace your Test
class):
class Test(Tag.body):
def init(self):
self.mylogin = MyInput()
self.mypass = MyInput()
#construct the layout
self <= Tag.div("Login:"+self.mylogin)
self <= Tag.div("Passwd:"+self.mypass)
self <= Tag.button("ok", _onclick=self.authent)
def authent(self,o):
if self.mylogin.value=="test" and self.mypass.value=="test":
self.clear()
self<= Tag.h1("You are in ;-)")
else:
self <= Tag.li("not the rights credentials ;-)")
You will notice that when you input bad credentials, the form is resetted to its initial values ! It's normal, because the authent
method will modify the Test
component's content (adding a Tag.li
to self
), which had the effect to force the redraw of the Test
component on UI side !
If you want to avoid this behaviour, simply add the Tag.li
in another part of the UI (or simply remove the last 2 lines), like that :
class Test(Tag.body):
def init(self):
self.mylogin = MyInput()
self.mypass = MyInput()
self.result = Tag.div()
#construct the layout
self <= Tag.div("Login: "+self.mylogin)
self <= Tag.div("Passwd: "+self.mypass)
self <= Tag.button("ok", _onclick=self.authent)
self <= self.result
def authent(self,o):
if self.mylogin.value=="test" and self.mypass.value=="test":
self.clear()
self<= Tag.h1("You are in ;-)")
else:
self.result <= Tag.li("not the rights credentials ;-)")
Because only self.result
(Tag.div) is modified ... only self.result
will be redraw on UI side.
Now, you should really understand 95% of the core htag features