Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Chrome Mobile (Nexus 7) | Form submission not working

I have an issue with logging into my website that appears to manifest in the mobile chrome browser (but works for the web-kit browser provided in some phones). I'm working trying to get into a "developer mode" on a tablet but I'm hoping someone else has run into this issue and can point me in the right direction while I figure out how to actually debug this.

Its a JSF2 Application (Primefaces over Bootstrap2.2) as the UI.

My form looks like this (second set of 'onblur' calls are intentional to see if that helped it--which it did not):

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:composite="http://java.sun.com/jsf/composite" 
>
    <composite:interface>
        <composite:attribute name="user" />
        <composite:attribute name="pass" />
        <composite:attribute name="error" />
        <composite:attribute name="loggedIn" />
        <composite:attribute 
            name="loginAction" 
            method-signature="void actionListener(javax.faces.event.ActionEvent)"
        />
        <composite:attribute 
            name="logoutAction" 
            method-signature="void actionListener(javax.faces.event.ActionEvent)"
        />
    </composite:interface>

    <composite:implementation>
        <script type="text/javascript">
        function copyValue(sourceId, targetId){
            var source = '#{cc.attrs.id}:' + sourceId;
            var target = '#{cc.attrs.id}:' + targetId;

            var sourceEl = document.getElementById(source);
            var targetEl = document.getElementById(target); 

            targetEl.value = sourceEl.value; 
        };
        </script>
        <h:form class="navbar-form pull-right" id="login" prependId="false" rendered="#{not cc.attrs.error and !cc.attrs.loggedIn}">
            <h:panelGroup rendered="#{!cc.attrs.loggedIn}" layout="span">
                <h:inputHidden value="#{cc.attrs.user}" id="userText"/>
                <h:inputHidden value="#{cc.attrs.pass}" id="passValue"/>

                <input 
                    class="span2" 
                    type="text" 
                    placeholder="Username" 
                    id="#{cc.attrs.id}:userText_a"
                >
                </input>
                <input 
                    class="span2" 
                    type="password" 
                    placeholder="Password"
                    id="#{cc.attrs.id}:passValue_a"
                >
                </input>

                <h:commandButton 
                    class="btn" 
                    value="Sign in"
                    onclick="copyValue('userText_a', 'userText'); copyValue('passValue_a', 'passValue');"
                    actionListener="#{cc.attrs.loginAction}"
                />
                <!-- onblur="copyValue('userText_a', 'userText'); copyValue('passValue_a', passValue);" -->
            </h:panelGroup>
        </h:form>

        <h:form class="navbar-form pull-right" id="login_error" prependId="false" rendered="#{cc.attrs.error and !cc.attrs.loggedIn}">
            <h:panelGroup rendered="#{!cc.attrs.loggedIn}" layout="span" styleClass="control-group error" style="display:inline-block;">
                <h:inputHidden value="#{cc.attrs.user}" id="userText_e"/>
                <h:inputHidden value="#{cc.attrs.pass}" id="passValue_e"/>

                <input 
                    class="span2" 
                    type="text" 
                    placeholder="Username" 
                    id="#{cc.attrs.id}:userText_b"
                    onblur="document.getElementById('#{cc.attrs.id}:userText_e').value = this.value;"
                >
                </input>
                <input 
                    class="span2" 
                    type="password" 
                    placeholder="Password"
                    id="#{cc.attrs.id}:passValue_b"
                    onblur="document.getElementById('#{cc.attrs.id}:passValue_e').value = this.value;"
                >
                </input>

                <h:commandButton 
                    class="btn" 
                    value="Sign in"
                    actionListener="#{cc.attrs.loginAction}"
                    onclick="copyValue('userText_b', 'userText_e'); copyValue('passValue_b', 'passValue_e');"
                />
                <br />
                <span style="color:orange;">Login failed: Invalid username or password</span>               
            </h:panelGroup>
        </h:form>

        <h:form class="navbar-form pull-right" rendered="#{cc.attrs.loggedIn}"> 
            <h:panelGroup class="span2" style="display: inline-block;">
                <h:commandLink 
                    value="#{cc.attrs.user} | Sign Out" 
                    class="btn btn-primary"
                    actionListener="#{cc.attrs.logoutAction}"
                />
            </h:panelGroup>
        </h:form>
    </composite:implementation>
</html>

To be clear, I can log in on the desktop using Chrome/IE8+/Firefox/Opera and mobile I only have the issue with Chrome (I have not tried an iOS browser yet). The password submission isn't copied to the values of the hidden input prior to the post.

This might not be the best design and I'm open to suggestion. Dragging in the <h:inputText /> components complicates the styling as I'm already replying heavily on Primefaces/Bootstrap and screws up the layout hence this "work-around".

like image 546
Daniel B. Chapman Avatar asked Nov 19 '12 21:11

Daniel B. Chapman


1 Answers

instead of

            <input 
                class="span2" 
                type="text" 
                placeholder="Username" 
                id="#{cc.attrs.id}:userText_b"
                onblur="document.getElementById('#{cc.attrs.id}:userText_e').value = this.value;"
            >
            </input>
            <input 
                class="span2" 
                type="password" 
                placeholder="Password"
                id="#{cc.attrs.id}:passValue_b"
                onblur="document.getElementById('#{cc.attrs.id}:passValue_e').value = this.value;"
            >
            </input>

            <h:commandButton 
                class="btn" 
                value="Sign in"
                actionListener="#{cc.attrs.loginAction}"
                onclick="copyValue('userText_b', 'userText_e'); copyValue('passValue_b', 'passValue_e');"
            />

try not setting an onblur property in the username and the password input, because the onBlur property may get tricky in mobile phones.

Instead, try doing everything inside the onClick event. i would do everything inside one function:

            <h:commandButton 
                class="btn" 
                value="Sign in"
                actionListener="#{cc.attrs.loginAction}"
                onclick="submitForm()"
            />

and inside the function:

function submitForm()
{
    var objUserText_e = document.getElementById('#{cc.attrs.id}:userText_e');
    var objUserText_b = document.getElementById('#{cc.attrs.id}:userText_b');

    var passValue_e = document.getElementById('#{cc.attrs.id}:userText_e');
    var passValue_b = document.getElementById('#{cc.attrs.id}:userText_b');

    objUserText_e.value = objUserText_b.value;
    passValue_e.value = passValue_b.value;

    /*
    copyValue('userText_b', 'userText_e'); copyValue('passValue_b', 'passValue_e');
    */

    // remove any return false
    // it will prevent the default event to be triggered (actionListener in this case)

}

i think this will submit the values without problems in the mobile version.

By the way, why duplicate the value of the inputs in the _e variables? can't you use the original _b ones? there are a lot of duplications sorry if i'm not getting why you do them.

SIDENOTE:

the same goes for the other form of id "login"

in the onClick event, just perform one action. multiple actions are not peformed by some browsers, so, insted of:

            <h:commandButton 
                class="btn" 
                value="Sign in"
                onclick="copyValue('userText_a', 'userText'); copyValue('passValue_a', 'passValue');"
                actionListener="#{cc.attrs.loginAction}"
            />

do this:

            <h:commandButton 
                class="btn" 
                value="Sign in"
                onclick="submit()"
                actionListener="#{cc.attrs.loginAction}"
            />

and you can perform the copyValue thing inside submit function:

function submit()
{
    copyValue('userText_a', 'userText');
    copyValue('passValue_a', 'passValue');
}

this way you will get the most cross-broser compatible code possible.

and again, try avoiding copyValue if possible. cheers

like image 132
canolucas Avatar answered Sep 20 '22 10:09

canolucas