KnockoutJS Required / Disabled attributes not removed - javascript

So I have a knockout prototype where you add inputs dynamically and then set each of their own settings. Think of its as a form builder is such. However, I noticed that disabled and required doesn't work that great. It sets the value to disabled or required but when I turn it into false it still remains on the element without its state, causing it to still function. Please can anyone help or give guidance.
HTML
<div class="leftpanel">
<div class="input-row" data-bind="foreach: inputItems">
<div class="input-row-item">
<div class="input-item">
<label data-bind="text: label"></label>
<input data-bind="attr:{ name: name, placeholder: placeholder, disabled: disabled, value: value, type: type }">
</div>
<div class="input-settings">
<input type="text" class="nb-remove" data-bind="value: label" placeholder="input label">
<input type="text" value="text" class="nb-remove" data-bind="value: type" placeholder="input type">
<input type="text" class="nb-remove" data-bind="value: name" placeholder="input name">
<input type="text" class="nb-remove" data-bind="value: placeholder" placeholder="input placeholder">
<input type="text" class="nb-remove" data-bind="value: disabled" placeholder="input disabled">
<input type="text" class="nb-remove" data-bind="value: value" placeholder="input value">
</div>
</div>
</div>
</div>
<div class="rightpanel">
Here be draggables!
<br/>
<button data-bind="click: addInput">ADD TEXT INPUT</button>
</div>
The JS
$(function(){
var InputItem = function InputItem(label, type, name, placeholder, disabled, value) {
this.label = ko.observable(label);
this.type = ko.observable(type);
this.name = ko.observable(name);
this.placeholder = ko.observable(placeholder);
this.disabled = ko.observable(disabled);
this.value = ko.observable(value);
}
var ViewModel = function ViewModel() {
var that = this;
this.inputItems = ko.observableArray([]);
this.addInput = function addInput() {
that.inputItems.push(new InputItem());
};
}
ko.applyBindings(new ViewModel());
});

You better use Knockout's own built-in disable binding-handler:
<input data-bind="disable: disabled, attr: { name: name, placeholder: placeholder, value: value, type: type }" />
See Fiddle
Alternatively, you can check for explicit 'truthfulness' in your condition so that Knockout will remove the attribute if the condition is not met. For example:
<input data-bind="attr: { disabled: disabled() === 'true', ...}" />
See this Fiddle (type 'true' in the 'disabled' input to activate disabled).

Related

How to bind tokenData parameters of stripe.createToken() to inputs with ngModel

I'm trying to create charge using a token created with stripe elements on the front end. I want to add the customers address by binding the different properties of tokenData with ngmodel to inputs, then passing the tokenData object as the second argument of the createToken() method.
//component.html
<input type="text" [(ngModel)]="name" placeholder="name" name="name">
<input type="text" [(ngModel)]="address_line1" placeholder="adress line 1" name="address">
<input type="text" [(ngModel)]="address_line2" placeholder="adress line 2" name="address">
<input type="text" [(ngModel)]="address_city" placeholder="City" name="city">
<input type="text" [(ngModel)]="address_state" placeholder="State" name="state">
<input type="text" [(ngModel)]="address_country" placeholder="Country" name="country">
<button (click)="submitForm()">Submit Payment</button>
//component.ts
public tokenData = {
name: '',
address_line1: '',
address_line2: '',
address_city: '',
address_state: '',
address_zip: undefined,
address_country: ''
};
public submitForm = () => {
this.stripe.createToken(this.card, this.tokenData).then(res => {
if(res.error){
console.log(res.error.message);
}
else {
this.stripeTokenHandler(res.token).subscribe();
console.log(res.token);
}
});
};
public stripeTokenHandler(t){
return this.http.post(`${this.apiUrl}/charge`, t);
};
but when I submit the form the token gets logged to the console with the tokenData parameters empty, which means that the inputs aren't getting binding properly to tokenData. How can this be done?
You are not binding to the properties of the tokenData, add tokenData to all your bindings like [(ngModel)]="tokenData.address_line1"
<input type="text" [(ngModel)]="tokenData.name" placeholder="name" name="name">
<input type="text" [(ngModel)]="tokenData.address_line1" placeholder="adress line 1" name="address">
<input type="text" [(ngModel)]="tokenData.address_line2" placeholder="adress line 2" name="address">
<input type="text" [(ngModel)]="tokenData.address_city" placeholder="City" name="city">
<input type="text" [(ngModel)]="tokenData.address_state" placeholder="State" name="state">
<input type="text" [(ngModel)]="tokenData.address_country" placeholder="Country" name="country">

Using Jquery bootstrap validation to validate individual field in an array of fields along with sibling field

I have a form with form-groups each containing similar text fields and checkboxes which are sent as arrays when submitting the form as below:
<form method="POST" action="http://localhost/save-form" id="formAddUser">
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
<div class="form-group">
<input type="text" class="name" name="username[]" />
<input type="text" class="phone" name="phone[]" />
<input type="text" class="country" name="country[]" />
<input type="checkbox" class="isMobile" name="isMobile[]" />
</div>
</form>
After every time someone enters their phone, I want to do a remote validation but I would like to send isMobile field along with the request. Currently I am able to send the phone field for validation but couldn't send the corresponding mobile field along with it in the data attribute. Here is my code
$('#frmAddUser').bootstrapValidator({
fields: {
'phone[]': {
trigger: 'blur',
validators: {
notEmpty: {
message: ' '
},
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
// leaving this empty just sends the phone. How do I send isMobile parameter along with this?
}
},
callback: {
callback: function () {
}
}
}
}
}
})
Edit: The following worked.
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
var isMobile = validator.getFieldElements('isMobile[]').val()
}
},
As suggested by #Sumesh, using validator.getFieldElements('isMobile[]').val() worked
remote: {
message: 'Phone does not exist',
url: 'http://localhost/verify-phone',
data: function () {
var isMobile = validator.getFieldElements('isMobile[]').val()
}
}

Convert input fields to Json in javascript

I would like to get a json result from my input fields.
Json Result
[{ScheduledVisit: "09/06/2017 12:00 AM", Company: "ABC Corp.", ContactPerson: "Someone"}]
The reason for that is because I want it to fit my class of
public class ScheduleVisit
{
[Required(ErrorMessage = "* Required")]
public DateTime ScheduledVisit { get; set; }
public string Company { get; set; }
public string ContactPerson{ get; set; }
}
I do not want to use the $("inputForm").serialize(); because I want to learn how to do this manually.
Below is my input form
<div class="col_half">
<input type="text" name="ScheduledVisit" placeholder="Scheduled Visit" class="sm-form-control border-form-control datetimepicker" id="ScheduledVisit" />
</div>
<div class="col_half col_last">
<input type="text" name="company" class="sm-form-control border-form-control" placeholder="company" id="company" />
</div>
<div class="col_two_third">
<input type="text" name="contactPerson" placeholder="Contact Person" class="sm-form-control border-form-control" id="contact" />
</div>
Please help. Thank you.
You can iterate <form> .elements, set each .name and .value as property and values of a FormData() object which can be submitted to server using fetch() or XMLHttpRequest(), or set properties and values at a JavaScript object which can be passed to JSON.stringify()
const form = document.forms[0];
form.onsubmit = e => {
e.preventDefault();
const fd = new FormData();
const props = {};
for (let element of form.elements) {
if (element.type !== "submit") {
props[element.name] = element.value;
fd.append(element.name, element.value);
}
}
for (let [key, prop] of fd) {
console.log(key, prop)
}
const json = JSON.stringify(props);
console.log(json);
}
<form>
<div class="col_half">
<input type="text" name="ScheduledVisit" placeholder="Scheduled Visit" class="sm-form-control border-form-control datetimepicker" id="ScheduledVisit" />
</div>
<div class="col_half col_last">
<input type="text" name="company" class="sm-form-control border-form-control" placeholder="company" id="company" />
</div>
<div class="col_two_third">
<input type="text" name="contactPerson" placeholder="Contact Person" class="sm-form-control border-form-control" id="contact" />
</div>
<input type="submit">
</form>
You can make object constructors that resemble your backend code. Here, I am serializing the inputs into a scheduleVisit object.
function scheduleVisit(obj) {
this.scheduledVisit = obj.scheduledVisit;
this.company = obj.company;
this.contactPerson = obj.contactPerson;
}
document.getElementById('button').addEventListener('click', function() {
var scheduledVisit = document.getElementById('ScheduledVisit').value;
var company = document.getElementById('company').value;
var contactPerson = document.getElementById('contact').value
var visit = new scheduleVisit({
scheduledVisit: scheduledVisit,
company: company,
contactPerson: contactPerson
});
console.log(JSON.stringify(visit));
});
<div class="col_half">
<input type="text" name="ScheduledVisit" placeholder="Scheduled Visit" class="sm-form-control border-form-control datetimepicker" id="ScheduledVisit" />
</div>
<div class="col_half col_last">
<input type="text" name="company" class="sm-form-control border-form-control" placeholder="company" id="company" />
</div>
<div class="col_two_third">
<input type="text" name="contactPerson" placeholder="Contact Person" class="sm-form-control border-form-control" id="contact" />
</div>
<button id=button>Submit</button>
You can assign the value of your inputs to an object manually. See below snippet for example. You can then serialize the object into a JSON formatted string.
let obj = {};
obj.ScheduledVisit = document.getElementById("ScheduledVisit").value;
obj.Company = document.getElementById("company").value;
obj.Contact = document.getElementById("contact").value;
console.log(obj);
let jsonStringObj = JSON.stringify(obj);
console.log(jsonStringObj);
<div class="col_half">
<input type="text" name="ScheduledVisit" placeholder="Scheduled Visit" class="sm-form-control border-form-control datetimepicker" value="testVisit" id="ScheduledVisit" />
</div>
<div class="col_half col_last">
<input type="text" name="company" class="sm-form-control border-form-control" placeholder="company" value="testCompany" id="company" />
</div>
<div class="col_two_third">
<input type="text" name="contactPerson" placeholder="Contact Person" class="sm-form-control border-form-control" value="testContact" id="contact" />
</div>
Using pure javascript you can do JSON.stringify(yourInputValu) to convert any javascript object to JSON
If your input form is that simple and you don't want a more generic solution, you could do it pretty easily with:
function get( id ) { return document.getElementById(id).value; }
var json = JSON.stringify({
ScheduledVisit: get('ScheduledVisit'),
Company: get('company'),
Contact: get('contact')
});

I can't reach dynamic inputs with javascript

I want to change Cloudera Hue project code but I have some problems.
Knockout data-bind is created some html codes with foreach , when I want to reach input in this html, my code does not work correct. My app.mako file code :
.....
<div data-bind="foreach: submissionVariables" style="margin-bottom: 20px">
<div class="row-fluid">
<span data-bind="text: name" class="span3"></span>
<input type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }" class="span9" />
<button class="btn fileChooserBtn" data-bind="click: $root.showTimePicker">time</button>
</div>
</div>
<input type="text" value="2014/03/15 05:06" id="datetimepickerz"/>
....
<script src="/static/js/jquery.datetimepicker.js"></script>
<script type="text/javascript">
$('#dtpickerfolder').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
$('#dtpickereverything').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
$('#datetimepickerz').datetimepicker()
.datetimepicker({value:'2015/04/15 05:03',step:10});
</script>
Output:
<input id="dtpickerfolder" class="span9" type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }"></input>
<input id="dtpickereverything" class="span9" type="text" data-bind="value: value,attr: { id: 'dtpicker' + name }"></input>
<input id="datetimepickerz" type="text" value="2014/03/15 05:06"></input>
datetimepickerz input works correct but my dynamic inputs that ids starts with dtpicker are not working.
Can anyone help me ?
I solve this with :
self.runOrShowSubmissionModal = function runOrShowSubmissionModal() {
var script = self.currentScript();
if (! $.isEmptyObject(script.getParameters())) {
self.submissionVariables.removeAll();
$.each(script.getParameters(), function (key, value) {
self.submissionVariables.push({'name': key, 'value': value});
// CALL TO JQUERY
$("#dtpicker"+key).datetimepicker({value:"2015/04/15 05:03",step:10});
});
$("#runScriptBtn").button("reset");
$("#runScriptBtn").attr("data-loading-text", $("#runScriptBtn").text() + " ...");
$("#submitModal").modal({
keyboard: true,
show: true
});
} else {
self.runScript();
}
};
I sent my jquery in knockout function.

Angular data in dropdown not set the second time

I've something weird going on here with Angular.
I have a details view with an edit button. When I press the edit button, I pass the object to the edit view. On the edit form there are a few dropdown boxes. The first time I click the edit button, everything loads well. All the dropdowns has the correct value selected. When I press cancel on the edit form, I get back to the details view. When I do nothing and press the Edit button again on the details view, the dropdowns don't have selected values at all! However the dropdowns do have items.
How is this possible? I didn't do anything with the data!
The details view and edit view are both directives:
In the template of customerDetails:
<div>
Here all the details of the customer
<button ng-click="ShowCustomerEditForm()">Edit</button>
</div>
<customer-edit
visible="showCustomerForm"
customer = "customer">
</customer-edit>
directive customer-edit:
app.directive("customerEdit", function (CustomerService, CountryService) {
return {
restrict: 'E',
templateUrl: '/Customer/Add',
scope: {
customer: '=',
visible: '=',
onCustomerSaved: '&'
},
link: function (scope, element, attributes) {
CustomerService.getAllAcademicDegrees().then(function (response) {
scope.academicDegrees = response;
});
CustomerService.getAllGenders().then(function (response) {
scope.genders = response;
});
CountryService.getAllCountries().then(function (response) {
scope.countries = response;
});
scope.$watch('customer', function (newValue) {
if (newValue && newValue.Id > 0) {
scope.customer.originalCustomer = {};
angular.copy(scope.customer, scope.customer.originalCustomer);
}
});
scope.customerFormSubmit = function () {
if (scope.customer.Id > 0) {
editCustomer();
}
else {
addCustomer();
}
}
scope.hideCustomerForm = function (restoreOriginal) {
if (restoreOriginal) {
angular.copy(scope.customer.originalCustomer, scope.customer);
}
scope.visible = false;
}
// Private functions
function editCustomer() {
var editCustomer = createCustomer(scope.customer);
editCustomer.Id = scope.customer.Id;
CustomerService.editCustomer(editCustomer).then(editCustomerSucceeded);
scope.hideCustomerForm(false);
}
function editCustomerSucceeded(response) {
var uneditedCustomer = _.findWhere(scope.customers, { Id: response.Id });
angular.copy(response, uneditedCustomer);
}
function addCustomer() {
var newCustomer = createCustomer(scope.customer);
CustomerService.addCustomer(newCustomer).then(function (response) {
scope.onCustomerSaved({ customer: response });
scope.hideCustomerForm(false);
});
}
}
}
});
I am trying to fix this for 6 hours now and I just don't understand it and I'm getting very desperate.. I just don't know how to fix this and what's causing this. I really hope someone can help me..
edit:
The customer edit html:
<div class="add-edit-container">
<div class="titleBox">
{{ customerFormData.title }}
<span class="close" title="Annuleren en sluiten" ng-click="hideCustomerForm(true)">×</span>
</div>
<div class="border">
<form id="frmAddCustomer" name="form" novalidate data-ng-submit="customerFormSubmit()">
<div>
<fieldset>
<legend>Identificatie</legend>
<label>Code:</label>
<input type="text" data-ng-model="customer.Code" />
<label>Geslacht:</label>
<label style="float: left;margin-right: 3px;" data-ng-repeat="gender in genders" data-ng-hide="$first">
<input type="radio" name="gender" data-ng-value="gender" data-ng-model="customer.Gender" />{{gender.Description}}
</label>
<div class="clear-float"/>
<label>Titel:</label>
<select data-ng-model="customer.AcademicDegree" data-ng-options="degree.Description for degree in academicDegrees"></select>
<label>Initialen:</label>
<input type="text" required data-ng-model="customer.Initials" />
<label>Voornaam: </label>
<input type="text" required data-ng-model="customer.FirstName" />
<label>Tussenvoegsel:</label>
<input type="text" data-ng-model="customer.MiddleName" />
<label>Achternaam:</label>
<input type="text" required data-ng-model="customer.LastName" />
<label>Geboortedatum:</label>
<input type="text" datepicker="01-01-1950" required data-ng-model="customer.BirthDate" />
<label>BSN:</label>
<input type="text" required data-ng-model="customer.BSNNo" />
<label>Identificatienummer:</label>
<input type="text" required data-ng-model="customer.IdCardNo" />
</fieldset>
<fieldset>
<legend>Contact</legend>
<label>Straat:</label>
<input type="text" required data-ng-model="customer.Street" />
<label>Huisnummer + toevoeging:</label>
<input type="text" required data-ng-model="customer.HouseNumber" style="width: 50px"/>
<input type="text" data-ng-model="customer.HouseNumberAddition" style="width: 50px"/>
<label>Postcode:</label>
<input type="text" required data-ng-model="customer.ZipCode" />
<label>Woonplaats:</label>
<input type="text" required data-ng-model="customer.City" />
<label>Telefoonnummer overdag:</label>
<input type="text" required data-ng-model="customer.DayPhone" />
<label>Telefoon anders:</label>
<input type="text" data-ng-model="customer.PhoneOther" />
<label>E-mailadres:</label>
<input type="email" required data-ng-model="customer.EmailAddress" />
<label>Bedrijfsnaam:</label>
<input type="text" data-ng-model="customer.CompanyName" />
<label>Land:</label>
<select data-ng-model="customer.Country" data-ng-options="country.Description for country in countries"></select>
</fieldset>
<fieldset>
<legend>Afwijkend postadres</legend>
<label>Straat:</label>
<input type="text" data-ng-model="customer.OtherStreet" placeholder="leeg indien niet van toepassing" />
<label>Huisnummer + toevoeging:</label>
<input type="text" data-ng-model="customer.OtherHouseNumber" style="width: 50px"/>
<input type="text" data-ng-model="customer.OtherHouseNumberAddition" style="width: 50px"/>
<label>Postcode:</label>
<input type="text" data-ng-model="customer.OtherZipCode" placeholder="leeg indien niet van toepassing" />
<label>Woonplaats:</label>
<input type="text" data-ng-model="customer.OtherCity" placeholder="leeg indien niet van toepassing" />
<input type="hidden" data-ng-model="customer.OtherAddressId" />
</fieldset>
</div>
<div class="button-box">
<input type="submit" value="Opslaan" class="button" />
Annuleren
</div>
</form>
</div>
</div>
I can answer why this problem is happening.
The problem is:
angular.copy(scope.customer.originalCustomer, scope.customer);
angular.copy does a deep copy. After the above call, scope.customer.Country, for instance, is a brand new object, it's not an element of scope.countries anymore. Therefore, the select directives lost track of the selected values.

Categories