Dynamic button enable knockout js based on error group - javascript

I have a text box and a button. When the text box is empty, I need the button to be disabled and when I start typing in the text box, I want the button to be enabled.
Currently, after inputing some text in the text box, the button is enabled the moment I focus out of the text box. But I want this to be enabled the moment is text box is not empty. I am using knockout.js and both my text box and the button are observables.
I have nore than 1 text field and I want to enable if all fields are not empty. If any field is empty, without loosing focus, I want to disable the button
Here's my code:
var email = ko.observable({ emailField: ko.observable().extend({ email:
true, required: { param: true, message: FILL_FIELD } })), enableButton
= ko.observable(), errorGroup = ko.validation.group([emailField]);
<input type="text" data-bind="value:emailField" />
<button data-bind="enable: enableButton>Press Next to enter password</button>

You have two options:
Use textInput for KO 3.2.0 and higher; or
Use value alongside valueUpdate: 'afterkeydown' for lower versions;
Both make sure your view model is updated immediately after key presses, cascading to other bindings like enable.

The thing that complicates your question is that you've got validation going on, and you want the validation to wait until focus exits, so having the values update continuously with your typing is not a solution.
Instead, you could watch input events separately, to keep track of which of your required fields are empty. watchForEmpty is a factory that takes an observable and returns a Knockout event handler. It sets up the initial state of the list of empties, and the event handler maintains it. The button is enabled when the list of empties has no entries.
vm = {
empties: ko.observableArray(),
thing: ko.observable('prefilled'),
thing2: ko.observable(),
watchForEmpty: function(observable) {
var initVal = observable();
if (initVal === '' || initVal === undefined) {
vm.empties.push(observable);
}
return function(context, event) {
var el = event.target;
if (el.value === '') {
vm.empties.push(observable);
} else {
vm.empties.remove(observable);
}
};
}
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<input data-bind="value: thing, event: {input: watchForEmpty(thing)}" />
<input data-bind="value: thing2, event: {input: watchForEmpty(thing2)}" />
<button data-bind="enable: empties().length === 0">Go</button>
<div data-bind="text: thing"></div>
<div data-bind="text: thing2"></div>

Related

click event on button is disabling the default behavior of html required

<input name="color" type="radio" data-bind="style: { backgroundImage : 'url('+$parents[1].generateSwatchImage($data)+')'}, checked: $parent.selectedOption, checkedValue: $data ,click : $parents[1].onSelectSwatchAddSlick" required />
<select name="size" required aria-required="true" id = "CC-prodDetails-sku-alphaProduct_size" data-bind="validatableTarget: selectedOption, validationOptions: {decorateElement: false, decorateElementOnModified: false}, options: optionValues, optionsText: 'key',
optionsCaption: $data.optionCaption, value: $data.selectedOption, disable: $parent.disableOptions() || $data.disable, optionsAfterRender: function(option, item) { ko.applyBindingsToNode(option, {disable: !item}, item); },onRender : $parent.AlphaSelector(), event : {change : $parents[1].onSelectDropdownOptionAddSlick}">
</select>
handleAddToCart: function() {
notifier.clearError(this.WIDGET_ID);
var variantOptions = this.variantOptionsArray();
notifier.clearSuccess(this.WIDGET_ID);
//get the selected options, if all the options are selected.
var selectedOptions = this.getSelectedSkuOptions(variantOptions);
var selectedOptionsObj = { 'selectedOptions': selectedOptions };
//adding availabilityDate for product object to show in the edit summary
//dropdown for backorder and preorder
var availabilityDateObj = { 'availabilityDate': this.availabilityDate()};
var stockStateObj = { 'stockState': this.stockState()};
var newProduct = $.extend(true, {}, this.product().product, selectedOptionsObj,
availabilityDateObj, stockStateObj);
if(this.selectedSku() && ! this.selectedSku().primaryThumbImageURL){
this.assignSkuIMage(newProduct, this.selectedSku());
}
if (this.variantOptionsArray().length > 0) {
//assign only the selected sku as child skus
newProduct.childSKUs = [this.selectedSku()];
}
newProduct.orderQuantity = parseInt(this.itemQuantity(), 10);
var itemQuantityInCart = this.itemQuantityInCart(newProduct);
var stockAvailable = newProduct.orderLimit&&newProduct.orderLimit<this.stockAvailable()?newProduct.orderLimit:this.stockAvailable();
if ((itemQuantityInCart + parseInt(this.itemQuantity(), 10)) > stockAvailable) {
var notificationMsg = CCi18n.t('ns.productdetails:resources.totalItemQuantityExceeded', {stockAvailable: stockAvailable, itemQuantityInCart: itemQuantityInCart});
notifier.sendError(this.WIDGET_ID, notificationMsg, true);
return;
}
$.Topic(pubsub.topicNames.CART_ADD).publishWith(
newProduct,[{message:"success"}]);
// To disable Add to cart button for three seconds when it is clicked and enabling again
this.isAddToCartClicked(true);
var self = this;
setTimeout(enableAddToCartButton, 3000);
function enableAddToCartButton() {
self.isAddToCartClicked(false);
};
if (self.isInDialog()){
$(".modal").modal("hide");
}
},
I am using required in html tags like input and select but the issue is default popover validation of required seems not to be working
if i use the click on event on button and if i remove that event the require starts working as expected
could someone help ??
<div id="CC-prodDetails-addToCart" data-bind="inTabFlow:(validateAddToCart())" >
<button type = "submit" class="btn primary full-width cart" data-bind="click: handleAddToCart" >
</button>
</div>
return true on the basic click event is the key
jsClick = function () {
console.log('jsClicked');
return true;
};
function MyViewModel() {
var self = this;
self.koClick = function () {
console.log('koClicked');
};
};
ko.applyBindings(new MyViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<button onClick="jsClick()" data-bind="click: koClick">click</button>
i think i have solved the issue i have added a data-bind submit on form tag and called the function there so the functionality and html required behavior both are working fine <form id="PDP_Form" data-bind = "submit : $data.handleAddToCart">
Why not just put a click handler on the submit button?
Heading
Instead of using submit on the form, you could use click on the submit button. However, submit has the advantage that it also captures alternative ways to submit the form, such as pressing the enter key while typing into a text box.
**
Parameters
**
Main parameter
The function you want to bind to the element’s submit event.
You can reference any JavaScript function - it doesn’t have to be a function on your view model. You can reference a function on any object by writing submit: someObject.someFunction.
Functions on your view model are slightly special because you can reference them by name, i.e., you can write submit: doSomething and don’t have to write submit: viewModel.doSomething (though technically that’s also valid).
Additional parameters
None
Notes
For information about how to pass additional parameters to your submit handler function, or how to control the this handle when invoking functions that aren’t on your view model, see the notes relating to the click binding. All the notes on that page apply to submit handlers too.

bootbox confirm: form not submitted on enter key press

I'm using bootbox to show a custom form to the user. Afterwards that form is used to modify the UI. Everything works fine, if I press the "Ok" button in the bootbox dialog. Pressing the ENTER button without touching the form (all values on default) also works properly. But if I put focus on one of my input fields and then press enter, my page just resets as if I pressed F5.
Can this be fixed?
My code:
bootbox.confirm({
message: "<form id='newGameForm' action=''>\
Playlist ID: <br> \
<input type='text' name='playlistID' size='35'/><br>\
Ruleset: <br>\
<input type='radio' name='rules' value='classic' checked> Classic\
<input type='radio' name='rules' value='adv'> Advanced\
</form>",
callback: function (result) {
if (result) {
let newGameParams = $('#newGameForm').serializeArray().reduce(function (obj, item) {
obj[item.name] = item.value;
return obj;
}, {});
initGame(newGameParams);
}
}
});
Edit: I found out that pressing enter while focusing the form is circumventing the bootbox's submit and instead uses the form's own submit. This adds ?playlistID=ABC123&rules=classic to the url and reloads the page. Can I somehow reroute the submit?
This isn't how the confirm helper is intended to be used - your use-case pretty much requires you to use the dialog helper. At a minimum, to make what you have probably work, you would need to capture the onsubmit event of the form you're inserting into the dialog.
Here's an example. I also moved your form out to a template script tag, since it makes the rest cleaner:
Template:
<script type="text/template" id="form-template">
<form id="newGameForm" action="">
Playlist ID: <br>
<input type="text" name="playlistID" size="35"><br>
Ruleset: <br>
<label><input type="radio" name="rules" value="classic" checked> Classic</label> <br>
<label><input type="radio" name="rules" value="adv"> Advanced</label> <br>
</form>
</script>
JavaScript:
var template = $('#form-template').html();
var $dialog = bootbox.confirm({
message: template,
callback: function (result) {
if (result) {
let newGameParams = $('#newGameForm').serializeArray().reduce(function (obj, item) {
obj[item.name] = item.value;
return obj;
}, {});
initGame(newGameParams);
}
}
});
$dialog.on('shown.bs.modal', function(e){
var $form = $('#newGameForm');
$form.on('submit', functino(fe){
fe.preventDefault();
$dialog.find('.btn-primary').trigger('click');
});
});
This only works if you do not override the btn class on the confirm button, but as-is, basically triggers a click on the confirm button when the embedded form is submitted. This example hooks into the form's submit event on the shown.bs.modal event (that link is for Bootstrap 4, but the same event is available in Bootstrap 3).

How to make it mandatory to select a value in Autoselect while using template

Scenario : we have a Kendo UI template. When a user tries to type atleast 2 charters data is populated in Autocomplete widget. I cannot use combobox as return data may be huge and combobox freezes. I want to force user to select a option from Auto complete dropdown and if nothing is returned from autocomplete or if user not select a data I want to clear the text field.The issue with my code is that everytime it clears the first row in the template and not the relevant one where data is not selected.
Template declaration
<script id="newTestTemplate" type="text/x-kendo-template">
<div id="testRec">
<input id="pSearchId" class="pSearch"
data-role="autocomplete"
data-placeholder="Select from dropdown"
data-text-field="name"
type="text"
data-bind="source: pSearchDS, value: name, events: {select: pSelected,open : pOpen,close : pClose}"
data-min-length="2"
data-highlight-first="true" maxlength="160" />
<input id="pDesc" data-role="textbox" placeholder="Description" class="k-textbox part-input" data-bind="value: description/> </div>
Javascript:
pOpen = function (e) {
valid = false;
}
pClose = function (e) {
if (!valid) {
$(e.sender).closest(".pSearch").val("");
$("#pDesc").val(''); //tried this way too
}
}
pSelected = function (e) {
valid = true;
}
Please suggest . If there is anyother way to force implement selection then let me know that too.
You can try the following on Autocomplete blur check if the user selected any value if not clear the values
$("#pSearchId").blur(function(){
if (!valid) {
alert("User not selected any value");
$("#pSearchId").val('');
$("#pDesc").val('');
}
});
For this I ended up putting validation on the click even to check if text box have a value.

Meteor binding values for inputs with event generation

I have a form input with a value bound to a reactive data source:
<input type="text" name="first-name" id="first-name" required value="{{currentUser.profile.firstName}}" />
I want to watch 'change' events on the input:
$('#first-name').change(function() { alert('Value changed!'); });
This works fine if I change the value directly in the input. However, if the value changes reactively, the change event doesn't fire.
What's the best way to bind values to form elements so that the 'change' event fires if the reactive data source changes?
The Optimum Solution would be to use manuel:viewmodel. You keep the state of the UI in a javascript object and bind the UI elements to properties of that object.
Example :
First add the package to the project with meteor add manuel:viewmodel
Then in the Html do the Following :
<template name="loginBox">
First Name: <input type="text" data-bind="value: first"/>
<br/>
Last Name: <input type="text" data-bind="value: last"/>
<div data-bind="text: greeting"></div>
<a data-bind="enabled: canEnter, hover: showError" class="btn-primary">Enter Site</a>
<span data-bind="text: errorText" class="text-error"></span>
</template>
Then in the Javascript file do the Necessary Bindings
Template.loginBox.viewmodel({
first: '',
last: '',
greeting: function() {
return "Hello " + this.first() + " " + this.last();
},
canEnter: function() {
return !!this.first() && !!this.last();
},
showError: false,
errorText: function() {
if (this.canEnter() || !this.showError()) {
return '';
}
return "Please enter your first and last name";
}
});
Here we're binding the value of the input/text element to the property 'first' of the viewmodel.
The result is that the viewmodel object will be kept in sync with the input box. If you change the value in the texbox then the value of the viewmodel's 'first' property will also change and vice versa.
For More information http://viewmodel.meteor.com/
Here's my initial solution, which I'm not particularly thrilled with:
Template.signUpPersonalDetails.rendered = function() {
this.autorun(function() {
if (Meteor.user() && Meteor.user().userAccount) {
var userAccount = Meteor.user().userAccount;
$('#first-name').val(userAccount.firstName).change();
$('#last-name').val(userAccount.lastName).change();
$('#email').val(userAccount.email).change();
$('#phone-number').val(userAccount.phoneNumber).change();
$('#postcode').val(userAccount.shippingPostcode).change();
}
});
};

ng-model doesn't change value when field contains user input

I'm still fairly new to angular.js. This seems like it should be very simple, but I'm stumped.
I have an input field:
<input type="text" placeholder="Search" ng-model="search.txt">
And I have a button that calls this function in my controller on ng-click:
$scope.clearSearch = function() {
$scope.search = {txt:"qqqqq"};
}
Clicking the button behaves as expected - the input value on the page becomes "qqqqq". So the data binding seems correct.
However, if I type anything into the field first and then press the button, the input value does not change on the page - the input field keeps the value I typed. Why is that?
What I'm really trying to do is clear the field, I'm just using "qqqqq" for illustration - setting the value to null has the same behavior.
It works:
Script:
angular.module('myapp',[])
.controller('myctrl',function($scope){
$scope.search = {text:'some input'};
$scope.clearSearch = function () {
$scope.search={text:null};
}
});
Markup:
<div ng-app="myapp" ng-controller="myctrl">
<input type="text" ng-model="search.text"/>
<button ng-click="clearSearch()">clear</button>
</div>
In plunker

Categories

Resources