Iliad (session and statefull forms)

Tagged:

Hello again.

The weekend ends and I used today, to get a bit deeper into Iliad.

I created the login-dialog, which shows you, that if you open it again, the same data apears again that you already typed in and I used the session, to store a switch, if the user is logged in.

So, the first thing I did, was to overwrite the Application initialize method, to initialize the new switch, which I want to save into the session.

initialize [
    super initialize.
    self session preferenceAt: #userLoggedIn put: false.
]

The current session is in every subclass of IliadObject accessible throug #session.
So in every Widget or Application, the current session is available.

After the new switch is initialized, the next thing I did, was to enhance the Menu class, to have additional entries, if the user would be logged in.

I created a new instance-variable entriesLoggedIn and the appropriate #addEntryLoggedIn:withAction method. (It's the same as the addEntry:withAction method, it only accesses the new instance-variable.)

At the end of the initialize-method I added a:

self addEntryLoggedIn: 'Bla' withAction: [self redirectToLocal: '/'].

and at the end of the current contents method the following code:

(self session preferenceAt: #userLoggedIn)
    ifTrue: [
        entriesLoggedIn do: [ :each |
            (ul listItem anchor) text: each key; action: each value
        ]
    ]

Now let's create the login dialog. Therefore I enhanced (modified) the Login class that it looks afterward like:

UrPics.PageTemplate subclass: Login [
    | userName userPassword |

    userName [ ^userName ifNil: [userName := '']]
    userName: aName [userName := aName]

    userPassword [ ^userPassword ifNil: [userPassword := '']]
    userPassword: aPassword [userPassword := aPassword]

    mainContent [
        ^[ :e |
            | div form table row data |
            div := e div.
            div h1: 'Login'.
            form := div form.
            table := form table.
            row := table tableRow.
            row tableData text: 'Username:'.
            row tableData input
                value: self userName;
                size: 20;
                action: [:val | self userName: val].
            row := table tableRow.
            row tableData text: 'Password:'.
            row tableData password
                value: self userPassword;
                size: 20;
                action: [:val | self userPassword: val].
            row := table tableRow.
            row tableData.
            data := row tableData.
            data button
                action:  [self doLogin];
                text: 'Login'.
            data button
                action: [self redirectToLocal: '/'];
                text: 'Cancel'.
            e break; break.
        ]
    ]

    doLogin [
        self session preferenceAt: #userLoggedIn put: true.
        self redirectToLocal: '/'
    ]

]

Here, I setup 2 instance-variables (userName and userPassword) and created their accessor methods. Through these variables, the state will be saved through the different calls of the web-pages. (Okay, later on, we will have to make a small change in our Application, to have the state saved of the complete Login-page...)

But you can see, how to provide and save the data from and into these variables and the associated input-fields of the form. Look at the #value: and #action methods for the name and password input fields.

Additional you see how to handle a button. You can directly provide an action-block to the button, which will be evaluated, if the button is pressed. In the save-button case, we call the doLogin method of the class and in the cancel-button case, we go directly back to the homepage of our application.

If you now run the application, the login-dialog will appear and will basically do it's job, but it could not save the inputs of the dialog between subsequent displays of the different web-pages of our application. To achieve this, we have to do a littel modification in our Application-code.

We create an instance-variable for the Login class (loginView) and the accessor method:

    | loginView |

    loginView [
        ^loginView ifNil: [ loginView := Login new ]
    ]

And because, we are creating an instance of Login, if we need it and it doesn't currently exist, we could have a look at our old #login method, where we create every time we call login a new instance of the Login-class.

So we change the method to the following code:

login [
    
    ^[ :e |
        e add: self loginView build
    ]
]

That's all. You saw, how to enhance the session with additional data, and how to save the state of the widgets.

Happy coding!
Joachim.

User login