aurelia-ui-toolkits / aurelia-materialize-bridge

Materialize CSS components for Aurelia
http://aurelia-ui-toolkits.github.io/demo-materialize/
MIT License
155 stars 53 forks source link

Unable to set "name" property of <input> #487

Closed apboon closed 6 years ago

apboon commented 6 years ago

Hey guys! Thank you for the wonderful work ya'll did on the Aurelia Materialize Bridge. Its my first time front-ending in this new day and age of SPA and I am having a blast :)

I came across the following problem, searched the internet, searched the code, but could not find an official solution/approach and I think this might be a bug or simply something missing depending how you look at it.

There doesn't seem to be a way to set the name property of an inner elements like <input> when working with <md-input>. This causes every input field on every page to be known by their id attribute instead; e.g. "md-input-0", "md-input-1", etc.

So there's no way to name a password field "password" and a username field "username". This renders an application pretty much unworkable in terms of user experience when a user is using a password manager like LastPass; form completion dialogs keep popping up every time the user focuses on a form field anywhere in the application (because all fields pretty much have the same name).

I only had trouble with LastPass so far, but I can imagine more software is depending on the name attribute to understand the context of an input field.

The only element I've seen that has a name attribute implemented is the <md-radio> element.

Is there an official solution/approach for this? Or maybe a workaround like some generic format to set an attribute on a inner element like setting md-inner-input-name="username"?

Cheers!

adriatic commented 6 years ago

Since the browser is not safe from hackers (anyone can set a breakpoint in “developers view” in Chrome for example), you are advised not to take the approach you are trying to take. Instead, we recommend to use the services of a platform like Auth0, or Microsoft Identity, which properly address such vulnerabilities.

apboon commented 6 years ago

*properly puzzled* Thank you for your response. But I am sorry to say that I am having trouble relating this to my question. I don't see how they are related.

My question is about not being able to set a common name attribute of the (inner) <input>. (Now I am starting to doubt myself.. checking if the name attribute is still valid HTML5..)

Auth0 and Microsoft Identity are services I could choose to integrate into my API server. But I don't want to use these, I already use oauth2 server side and I think it is sufficient.. also I don't want to force people in giving access through a third party.

Regarding to the name attribute.. sure Auth0 and Microsoft Identity might be able to show the user a login page (for their services) with input fields having a proper name attribute set so that a password manager like LastPass understands what these fields are about....... but that's a whole long long way around just to present a login screen with input fields that a password manager like LastPass understands.

I am re-reading my question and my response.. trying to find where I might have missed something or to find where I might have explained things better.. but I don't really know how to improve my question..

So... to test if we're talking about the same thing I'm going to fire an absurd hyperbole question at you: Are you suggesting I am unable to create a proper login screen (this includes being able to set a common attribute like name) using Aurelia Materialize Bridge? (Because of course I can't stop each and every user from around the world from using LastPass :p)

apboon commented 6 years ago

Ah! I might have found a better way to explain my question maybe.. what if.. I just want to set the common name attribute of the inner <input> used in Aurelia Materialize Bridge's <md-input> for no apparent reason.. How would I go about this?

apboon commented 6 years ago

I have created a workaround.. it ain't pretty.. but it works..

I've created a file named library/amb.name.attribute.hotfix.js which contains the following code:

export class amb_name_attribute_hotfix
 {
  static attached()
   {
    // Get array of all <md-input> parent elements.
    let aryelMDInput = document.getElementsByTagName('md-input');

    console.log('Found ' + aryelMDInput.length + ' <md-input> elements.');

    // For each parent <md-input> element..
    for (let intMDInput_Index = 0; intMDInput_Index < aryelMDInput.length; intMDInput_Index++)
     {
      let elMDInput = aryelMDInput[intMDInput_Index];
      // Get md-input's md-name attribute conform <md-radio md-name="">.
      let strMDInput_Name = elMDInput.getAttribute('md-name');

      // If <md-input> has a name..
      if (strMDInput_Name)
       {
        // Then get the underlying <input> child element.
        let elInput = elMDInput.querySelector('input');

        // If the <input> child element is found and it has no 'name' attribute set..
        if (elInput && !elInput.getAttribute('name'))
         {
          console.log('Found <md-input md-name="' + strMDInput_Name + '"> parent with nameless <input>. Setting <input name="' + strMDInput_Name + '">');

          // Set <input name="..."> attribute.
          elInput.setAttribute('name', strMDInput_Name);
         }
        else
         {
          console.error('Aurelia Materialize Bridge got an update and now supports the common \'name\' attribute for <md-input>/<input> elements. You should remove this hotfix.');
          return;
         }
       }
     }
   }
 }

In my signup and signin pages I have added the following code:

import { amb_name_attribute_hotfix } from 'library/amb.name.attribute.hotfix';

export class .......
 {
  attached()
   {
    amb_name_attribute_hotfix.attached();
   }
 }

The templates will contain something similar to:

<md-input md-name="name_to_give_to_the_input_child_element">

This will not fix the problem with the <input> fields of the rest of the application (they are still missing name attributes).. but at least the fields of the sign up and sign in pages in will have properly named <input> fields. As a result, all non-sign up/non-sign in fields will not be confused with the fields on the sign up/sign in pages.. so no more "helpfully" nagging about offering to fill in forms with credentials when you actually just want to write an email or type in a keyword in a search :p

I've made sure the hotfix uses md-name attribute similar to the <md-radio> element and logs an error to console if the hotfix becomes obsolete.

Below two screen shots of how the application is understood with and without the name attribute / hotfix.

Before: screenshot_20171018_165523

Since every <input> is called "md-input-0", "md-input-1", etc. this is going to be a real problem.

After: screenshot_20171018_165316

At least now there is a difference between the <input> fields of the sign up/sign in pages and the rest of the application.

:+1: :)

adriatic commented 6 years ago

@apboon sorry for confusing you - my intent was only to point out the insufficiency of the solution you described, without touching the Materialize specific details of your question. I believe that @Thanood will address your issue, if you did not solve it to your satisfaction

I am particularly interested in authentication and authorization problems in Aurelia context, so I responded from that viewpoint.

Thanood commented 6 years ago

@apboon The native input is (kinda) "hidden" because we're using a custom element. So it cannot be accessed directly. Of course, you could always create a PR to add md-name.. 😏

Apart from that, you can access the native input with javascript. If, for example, you have an <md-input ref="myInput">, the native element ist available as myInput.input. Setting myInput.input.name should be easy, then.

You could even create a custom attribute which does just that and apply name to the element it's attached to. That attribute may even be reusable for some other elements.

apboon commented 6 years ago

@Thanood Thank you for your response. I know about the inner/hidden <input>.. I already used it to create the workaround / hotfix I supplied in this thread above. Its a generic workaround that does not require any manual code.. and that works conform the existing standard (see <md-radio>). So I'm good..

Before I created this workaround/hotfix, I did try to take what is already there in the <md-radio> element (which supports the md-name="" attribute) and apply it to <md-input>.. but I could not make heads or tails of how to set the project up (for development, testing, etc). This is prolly due to my own limitations. Otherwise I would have loved to add this missing piece to AMB; especially because of how important this is for a good functioning application.

If someone already has the AMB project set up and is familiar with its build and testing process, it would prolly be fairly easy to copy-paste md-name="" from <md-radio>.. I almost did.. but got stuck on testing.

Thanood commented 6 years ago

@apboon I'm really sorry for the late reply.

Well, testing consist mostly of trying the controls in the bridge application itself by creating a sample and check that it works. 😃

I guess you're talking about the unit tests. These are not very well developed. At the very beginning there was no good way to test Aurelia components (no aurelia-testing or StageComponent) and we had to somehow get along without that.

Of course, that all changed now but as the "create a sample and test the bridge app itself" was a workflow that "automatically" led to having samples in the documentation... Well, that approach worked well enough. 😃