How do I make a submit button using devexpress and knockout.js? - javascript

So I have an app that shows expenses of a person. I made the view to add a new expense, but I don't know how to make the save button so it saves the expense in the db and redirects to the list of expenses.
The view has many fields like this:
<div id="selBxChSt" data-bind="dxLookup: {
dataSource: dsExpenses,
valueExpr: 'NAME',
displayExpr: 'NAME',
title: 'Expense',
searchEnabled: true,
value: selectedExpense
}">
</div>
And not only dxLookup, also dxTagBox,dxDateBox and dxTextArea.
I made the reset button, to set all fields to their default value. But I don't know how to save them to the firebird db.
This is the html for the button:
<div class="Column" data-bind="dxButton: {icon: 'todo', text: 'Save', type: 'normal', onClick: expenseSave}"></div>
So now I have to make a function in knockoutJS to save all the things the user chooses from the lookups.
I have no idea how to do this, I'm new to knockout.js and devexpress, so any idea or tips would be amazing, thank you!

To implement "old-school" form that submits data to a server-side go this way:
Wrap all editors and submit button with the form tag.
Use the useSubmitBehavior option for dxButton.
Set the name option for editors.
Your code should be like below:
<form action="your-action" method="post" data-bind="event: { submit: onFormSubmit }">
<div data-bind="dxTextBox: { name: 'login' }"></div>
<!-- other editors... -->
<div data-bind="dxButton: { text: 'Submit', useSubmitBehavior: true }"></div>
</form>
View model:
viewModel.onFormSubmit = function() {
// Here you can implement a custom logic before submit. Validate editors, for instance.
};
Refer this sample, as well.

Related

Braintree JSv3 payment_method_nonce Value Bad With HostedFields

I have looked at a few posts on here with the same issue but under different circumstances that don't supply me with an answer to my particular issue...
I was using Braintree JSv2 with my Django project and all was working fine. Since I have migrated over to v3 of Braintree, the only issue I seem to have right now is that the value inputted to "payment_method_nonce" is not there...
Here is the code that is supposed to be dumping the payment_method_nonce value:
document.querySelector('input[name="payment_method_nonce"]').value = payload.nonce;
And here is the code that is supposed to be grabbing it on the python side:
client_payment_nonce = request.POST['payment_method_nonce']
When submitting this in my dev environment, I get an error (MultiValueDictKeyError) for "payment_method_nonce".
I am using Django 1.9 and Python 2.7. I am also using the example given by Braintree for a simple integration using HostedFields...
Small test
So I manually added an input field in my form with name "payment_method_nonce" just to see if not having a field was causing some issue. I know it is injected by Braintree but just testing a thought. It seems that although the value of payment_method_nonce is supposed to be my nonce, I didn't type anything into the input box and it was still coming back as null.
Full Snippets of Form and HostedFields
<form action="/booking/" method="post" id="checkout_form">
{% csrf_token %}
<div class="payment">
<span>Payment</span>
<!--input elements for user card data-->
<div class="hosted-fields" id="card-number"></div>
<div class="hosted-fields" id="postal-code"></div>
<div class="hosted-fields" id="expiration-date"></div>
<div class="hosted-fields" id="cvv"></div>
<div class="btns">
<input type="hidden" name="payment_method_nonce">
<input type="submit" value="Complete Booking" id="pay-button">
</div>
</div>
</form>
Note: I had just changed the payment_method_nonce field to type="hidden" instead of type="text" but still have the same effect...
<!-- load the required client component -->
<script src="https://js.braintreegateway.com/web/3.15.0/js/client.min.js"></script>
<!-- load the hosted fields component -->
<script src="https://js.braintreegateway.com/web/3.15.0/js/hosted-fields.min.js"></script>
<!-- Braintree setup -->
<script>
var client_token = "{{ request.session.braintree_client_token }}"
var form = document.querySelector('#checkout-form');
var submit = document.querySelector('input[type="submit"]');
braintree.client.create({
authorization: client_token
}, function (clientErr, clientInstance) {
if (clientErr) {
// Handle error in client creation
return;
}
braintree.hostedFields.create({
client: clientInstance,
styles: {
'input': {
'font-size': '14px'
},
'input.invalid': {
'color': 'red'
},
'input.valid': {
'color': 'green'
}
},
fields: {
number: {
selector: '#card-number',
placeholder: 'Credit Card Number'
},
cvv: {
selector: '#cvv',
placeholder: '123'
},
expirationDate: {
selector: '#expiration-date',
placeholder: '10/2019'
},
postalCode: {
selector: '#postal-code',
placeholder: '10014'
}
}
}, function (hostedFieldsErr, hostedFieldsInstance) {
if (hostedFieldsErr) {
// handle error in Hosted Fields creation
return;
}
submit.removeAttribute('disabled');
form.addEventListener('submit', function (event) {
event.preventDefault();
hostedFieldsInstance.tokenize(function (tokenizeErr, payload) {
if (tokenizeErr) {
// handle error in Hosted Fields tokenization
return;
}
// Put `payload.nonce` into the `payment_method_nonce`
document.querySelector('input[name="payment_method_nonce"]').value = payload.nonce;
document.querySelector('input[id="pay-button"]').value = "Please wait...";
form.submit();
});
}, false);
});
});
</script>
Note: the line document.querySelector('input[id="pay-button"]').value = "Please wait..."; doesn't fire (I know this because the button does not change values). Maybe these querySelector lines just aren't working?
Something New Noticed
I just went back to my page and hit the submit button without even entering any information. In v2 of Braintree, I would not be able to click the submit button until all fields were filled in... Maybe the values in my form aren't even being sent to braintree to receive a nonce and that's why there is an empty string being returned..?
Moral of the story
Review your code... Multiple times. As pointed out by C Joseph, I have my form ID as something different than what my var form is referencing...
<form action="/booking/" method="post" id="checkout_form">
var form = document.querySelector('#checkout-form');

How to set modelValue in Angular formly using custom template

I have create custom template to add todo list in angular formly. jsbin Link
I'm trying to add required validation but its not working. I have added validators to check. But viewValue, modelValue contains value in input field. Is there are any way to set modelValue in validator with actual model.
return [
{
className: 'col-sm-12 col-md-12 col-lg-12',
key: 'todoList',
type: 'todolist',
templateOptions: {
type: 'text',
label: 'Add todo list',
placeholder: 'Enter todo list'
},
validators: {
tagLength: {
expression: function(viewValue, modelValue) {
var value = modelValue || viewValue;
console.log(modelValue)
console.log(viewValue)
//return value.length > 0;
},
message: '"Altest 1 Operation is required"'
}
}
}
What i'm exactly trying to achive is, if todolist is empty then submit button should be disabled.
Thanks in advance.
This is completely unnecessary. All you have to do is set the ng-show in the submit button. No validators are needed. Just tested it on your jsbin link and it works as expected. Please mark this as the correct answer.
ng-show="vm.model.todoList.length > 0" OR
ng-show="vm.model.todoList" (since it will be false if empty/undefined)
Validators are to validate the input on THAT field, not for other fields/buttons.

Dynamically bind objects to inputs in angular

I have these objects right here that I will use to save data from a form, and later send it to an api as JSON :
$scope.price = {}
$scope.item = {"price":$scope.price, };
I also have these field which will be used to dynamically generate inputs on a html page:
$scope.fields = [
{
name: $scope.item.title,
title: 'Title',
type: {
view: 'input'
}
},
{
name: $scope.price.regular,
title: 'Regualar Price',
type: {
view: 'input'
}
}
];
Now in order to generate the form I use this code:
<div class="form-group" ng-repeat="field in fields">
<label>{{ field.title }}:</label>
<span ng-switch on="field.type.view">
<span ng-switch-when="input">
<input
ng-model=field.name
type="text"
/>
</span>
</span>
</div>
And with this code, it is not assigning the values in the input to the objects. Is there a way to do it? I know I can do it this way:
ng-model="item[field.name]"
But that limits me to only one level of the object. I want to be able to bind nested objects. And I just can't seem to figure it out. Thank You!

AngularJS - Binding radio button selection to model inside ng-repeat

I have a data model persons which takes the following form:
personsInfo = {
name: Adam
dob: 31-FEB-1985
docs: [
{
docType: Drivers License,
number: 121212,
selected: false
id: 1
},
{
selected: true,
docType: None
},
{
docType: State ID,
number: 132345,
selected: false,
id: 2
}
]
}
In my markup I have defined the following to dynamically generate radio buttons.
<div ng-repeat="personDoc in personsInfo.docs">
<input type="radio" name="personDocs" ng-model="personDoc.selected" value=""/>
{{personDoc.docType}} <span ng-hide="personDoc.docType === 'None'">Number: {{personDoc.number}}</span>
</div>
I want to be able to check the documents which have selected as true on page load, and then depending on what the user selects save the selected flag in my personsInfo model.
My intent here is to send the personsInfo model back to another page.
If somebody could point me to a working fiddle it would be greatly appreciated!
Thanks!
You're almost there just missing the binding to show which document is selected. We'll add an object to the scope to represent the selected item, then bind the forms to that model.
JS
app.controller('...', function($scope) {
$scope.personInfo = { ... };
$scope.selectedDoc = {};
$scope.$watch('personInfo',function() {
$scope.selectedDoc = $scope.personInfo.docs[0];
});
});
HTML
<div ng-repeat='doc in personInfo.docs'>
<input type='radio' ng-model='selectedDoc' value='doc' /> {{doc.docType}}
</div>
<form>
<input type='text' ng-model='selectedDoc.number' />
...
</form>

rendered called before DOM completion - meteor blaze

I am creating a dynamic form using json and trying to use jquery-validation plugin to add validation rules to input fields.
Json structure and helper method is :
var fields = [{
label: "Name",
type: {name: 'STRING'},
validationRules: {
required: true,
maxlength: 100,
minlength: 3
}
},{
label: "Currency",
type: {name: 'CHECKBOX'},
defaultValue: ['USD', 'INR'],
validationRules: {
required: true
},
sourceCollection: 'oNLFfi4L3zgNLhScv',
}] ;
Template.eventCreate.helpers({
fields: function(){
console.log("calling fields");
fields.forEach(function(field, index){
field.sourceCollectionData = StaticLists.find({_id: field.sourceCollection});
});
return fields;
}
});
Template looks like:
<template name="eventCreate">
<form id="newEventForm" class="form-horizontal">
{{#each fields}}
<div class="form-group">
<label class="col-xs-2 control-label">{{label}}</label>
<div class="col-xs-6">
{{#if equals type.name 'STRING'}}
<input name="{{label}}" id="{{label}}" class="form-control" placeholder="Enter {{label}}" value="{{defaultValue}}" />
{{/if}}
{{#if equals type.name 'CHECKBOX'}}
{{#each sourceCollectionData}}
{{#if isActive}}
<div class="col-xs-2 checkbox">
<label class="checkbox-inline">
<input type="checkbox" name="{{../label}}" id="{{../label}}" value="{{name}}" {{checked ../defaultValue}}> {{name}}
</label>
</div>
{{/if}}
{{/each}}
{{/if}}
</div>
</div>
{{/each}}
</form>
</template>
Now I am trying to add validation rule in rendered method:
Template.eventCreate.rendered = function(){
$('#newEventForm').validate({
....
});
fields.forEach(function(field, index){
if(field.validationRules){
$('#'+field.label).rules('add', field.validationRules);
}
});
}
It works in case of input text but throws exception for checkbox because checkbox DOM is still not laid out and there is no element with id "Currency".
I assume in meteor blaze rendered is called once only when DOM rendering is complete. Though it is called once here but before DOM rendering completes.
EDIT
Earlier I was hardcoding the JSON in js file itself and now I am retrieving it from mongo.
But its seems that rendered callback is invoked only first time and not invoked every time mongo collection changes(which in turn updates the DOM)
Template.eventCreate.helpers({
fields: function(){
var template = EventTemplate.findOne({name: 'Job Template'});
console.log("template", template);
if(template){
Session.set("template", template);
template.fields.forEach(function(field, index){
field.sourceCollectionData = StaticLists.find({_id: field.sourceCollection});
});
return template.fields;
}
}
});
Template.eventCreate.rendered = function(){
$('#newEventForm').validate({
...
...
console.log("rendering main template");
addValidationRules(Session.get('template'));
}
Now the console output is something like:
template undefined event_create.js?bfeba9389401dac358bc313bd9d4205818e356a1:52
rendering main template event_create.js?bfeba9389401dac358bc313bd9d4205818e356a1:98
template Object {_id: "iFDndmjavtFN8AdGQ", name: "Job Template", description: "Job Template", fields: Array[13]}
which shows that (and I tried it even with a break point in js script) that just when script loads template is undefined and no input field is rendered on front end but rendered callback is invoked. Now later when template gets populated with data, input fields are rendered but callback is not invoked again.
The recommended pattern is to put the contents of your {{#each}} blocks in separate templates and tap into the rendered event of those templates.
By the way, Meteor.defer is no longer required.

Categories

Resources