Knockout.js and Firefox Save passwords in login form

Firefox fills out the form with my username / password. This is using knockout.js to bind input, but it will not update the values ​​of this fill type. Am I missing something while loading the page? When it is populated and the user sends messages, the values ​​are empty.

(function (app, $, undefined) { app.viewModel = app.viewModel || {}; app.login = {}; app.viewModel.login = { userName: ko.observable(''), password: ko.observable(''), returnUrl: '' }; app.viewModel.login.submit = function () { sso.login(app.viewModel.login.userName(), app.viewModel.login.password(), app.viewModel.login.returnUrl); }; app.login.init = function (returnUrl) { app.viewModel.login.returnUrl = returnUrl; ko.applyBindings(app.viewModel); }; })(window.app = window.app || {}, jQuery); 
+8
firefox
source share
3 answers

The way I've been doing in the past is to use a wrapper to bind value , which initializes the value from the current value of the element.

It will look (this is simplified to work only with observables):

 ko.bindingHandlers.valueWithInit = { init: function(element, valueAccessor, allBindingsAccessor, context) { var observable = valueAccessor(); var value = element.value; observable(value); ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, context); }, update: ko.bindingHandlers.value.update }; 

So you would use valueWithInit instead of value . You just need to make sure ko.applyBindings is not called before autocomplete does its job.

http://jsfiddle.net/rniemeyer/TeFAX/

+5
source share

I found the solution here is not very satisfactory. Although the approach is quite interesting, it fails when the user selects an account later and the browser allows the use of stored credentials (for example, if multiple credentials are stored). This also failed when you started entering the password and deleted to return to the original password (at least in Firefox). Also, I didn’t really like the timeout to give the browser time - it’s just not so nice.

My solution: which is not really one, but I thought I was anyway

Just update our model manually before you login in the submit callback. Using jQuery, something like self.password($("#password").val()) should do this.

Alternatively, using existing bindings, triggering a change event also seems to work. $("#password").change() .

Pros:

  • Designed for credential fields only, so maybe one time for your site.
  • simple and clean - one or two lines in the right place
  • always works reliably, no matter which browser, credential setting or usage pattern

Against:

  • good separation is torn again. Knockout.js provides
  • - this is not a solution, but a workaround

I will stick to this because I found it just reliable work. It would be nice to say that Knockout revises the bindings directly, rather than saving the value back manually or triggering it through a change event. But I haven’t found anything yet.

Just think a little ahead - the same problem should occur when the browser automatically completes any form (for example, as an address) - this means that some general function that performs the above would be nice (perhaps by triggering a change trigger on each input field forms)

Edit: Quick code demonstrating the idea

HTML:

 <form id="myForm" data-bind="submit: login"> Email: <input type="text" data-bind="value: email" /><br/> Password: <input type="password" data-bind="value: password" /><br/> <button type="submit">Login</button> </form> 

And Javascript:

 function ViewModel() { var self = this; self.email = ko.observable(""); self.password = ko.observable(""); self.login = function() { $("#myForm").find("input").change(); //Now the observables contain the recent data alert(ko.mapping.toJSON(self)); }; } 
+3
source share

For additional information only:

In the SPA MVC 5 SPA template, the same thing happens.

I fixed this by reassigning the input values ​​to observable immediately before the login comes out:

in login.viewmodel.js

 // Operations self.login = function () { self.userName($("#LoginUserName").val()); self.password($("#LoginPassword").val()); //original 
0
source share

All Articles