durandal compose - how to use the same module in a loop in different parts of the page - durandal

This is a loop using knockout sortable:
<div data-bind="sortable: {data: Fields,beforeMove:$root.preOrder,afterMove:$root.saveOrder}">
<div class="item"><a data-bind="text:Name,click:function() {$root.edit(Id());}" style="margin-left:20px;"></a>
<!-- ko if: $root.selectedFieldId()==Id() -->
<!-- ko compose:{model:'tasktype/edittasktype/addedittasktype',activationData:{TaskTypeId:$root.TaskTypeId, Sections:$root.Sections,FieldId:$root.selectedFieldId,Dimensions:$root.Dimensions } } --><!-- /ko -->
<!-- /ko -->
</div>
</div>
But when the module loads and knockout binds to it, the bindings are broken, they don't update the observables in the module? Anyone know why?
The module is a singleton, because in this case I only intend to have one copy of it open at a time.
Can anyone suggest a different way to accomplish this?
Much appreciated.
The module code is quite extensive, so here is it is with just activate, I stripped out the other functions:
define(['plugins/http', 'durandal/app', 'knockout', 'plugins/ajax', 'plugins/dynamiccss', 'plugins/utility', 'durandal/global'], function (http, app, ko, ajax, cssLoader, utility,global) {
var vm = {};
vm.selectedFieldTypeId = ko.observable('1');
vm.newFieldName = ko.observable('');
vm.selectedFieldRequired = ko.observable(true);
vm.selectedPrecision = ko.observable(2);
vm.selectedMaxChars = ko.observable(5000);
vm.newSectionName = ko.observable();
vm.selectedSectionId = ko.observable('1');
vm.selectedDimensionId = ko.observable('1');
vm.activate = function (params) {
vm.TaskTypeId = params.TaskTypeId;
vm.Sections = params.Sections;
vm.FieldId = params.FieldId;
vm.Dimensions = params.Dimensions;
$('#addFieldName').focus();
if (vm.FieldId() != '0' && vm.FieldId() != undefined) {
return $.when(
ajax.wrap('TaskType/GetTaskTypeFieldType', { Id: '1' }, function (response) {
if (typeof vm.TaskTypeFieldTypes === 'undefined')
vm.TaskTypeFieldTypes = ko.mapping.fromJS(response.Model);
else
ko.mapping.fromJS(response.Model, {}, vm.TaskTypeFieldTypes);
}),
ajax.wrap('TaskType/GetTaskTypeFieldModel', {Id:vm.FieldId()}, function (response) {
if (typeof vm.FieldModel === 'undefined')
vm.FieldModel = ko.mapping.fromJS(response.Model);
else
ko.mapping.fromJS(response.Model, {}, vm.FieldModel);
vm.FieldId(vm.FieldModel.Id());
vm.selectedFieldTypeId(vm.FieldModel.TaskTypeFieldTypeId());
vm.newFieldName(vm.FieldModel.Name());
if (vm.FieldModel['Required'] != undefined)
vm.selectedFieldRequired(vm.FieldModel.Required());
if (vm.FieldModel['MaxLength'] != undefined)
vm.selectedMaxChars(vm.FieldModel.MaxLength());
if (vm.FieldModel['DimensionId'] != undefined)
vm.selectedDimensionId(vm.FieldModel.DimensionId());
if (vm.FieldModel['TaskTypeSectionId'] != undefined)
vm.selectedSectionId(vm.FieldModel.TaskTypeSectionId());
if (vm.FieldModel['Scale'] != undefined)
vm.selectedPrecision(vm.FieldModel.Scale());
})
);
}
else {
return $.when(
ajax.wrap('TaskType/GetTaskTypeFieldType', { Id: '1' }, function (response) {
if (typeof vm.TaskTypeFieldTypes === 'undefined')
vm.TaskTypeFieldTypes = ko.mapping.fromJS(response.Model);
else
ko.mapping.fromJS(response.Model, {}, vm.TaskTypeFieldTypes);
})
);
}
};
Here is the module HTML, these bindings don't work, the values load but when you lose focus they don't update the observables anymore:
<div style="padding-right: 20px; margin-top: 10px; padding-top: 5px; border-top: 1px solid LightGrey; border-bottom: 1px solid LightGrey;">
<span class="span3" style="margin-left:10px;">Field Name</span> <span class="span6"style="margin-left:0px;"><input type="text" id="addFieldName" data-bind="value:$root.newFieldName"></input></span> <span class="span3"><a class="btn icon-ban-circle" data-bind="click:function() {deleteField(FieldId());}"> Delete This Field</a></span>
<br style="clear:both;" />
<span class="span3" style="margin-left:10px;">Section</span> <select data-bind="options:$root.Sections, value:$root.selectedSectionId,optionsText:'Name',optionsValue:'Id'"></select><br />
<span class="span3" style="margin-left:10px;">Field Type</span>
<select title="Field types cannot be edited once set, you must delete and create a new field instead." data-bind="disable:FieldId()!=undefined&&FieldId()!='0',options:$root.TaskTypeFieldTypes, value:$root.selectedFieldTypeId,optionsText:'Name',optionsValue:'Id'"></select>
<br />
<!-- ko if: selectedFieldTypeId() == '2' --><!-- checkbox -->
<span class="span3" style="margin-left:10px;">Required</span> <input type="checkbox" data-bind="checked:$root.selectedFieldRequired" /><br />
<!-- /ko -->
<!-- ko if: selectedFieldTypeId() == '3' --><!-- date -->
<span class="span3" style="margin-left:10px;">Required</span> <input type="checkbox" data-bind="checked:$root.selectedFieldRequired" /><br />
<!-- /ko -->
<!-- ko if: selectedFieldTypeId() == '4' --><!-- text -->
<span class="span3" style="margin-left:10px;">Characters Max Length</span><input type="text" data-bind="value:$root.selectedMaxChars" /><br />
<span class="span3" style="margin-left:10px;">Required</span> <input type="checkbox" data-bind="checked:$root.selectedFieldRequired" /><br />
<!-- /ko -->
<!-- ko if: selectedFieldTypeId() == '5' --><!-- number -->
<span class="span3" style="margin-left:10px;">Precision</span><input type="text" data-bind="value:$root.selectedPrecision" /><br />
<span class="span3" style="margin-left:10px;">Required</span><input type="checkbox" data-bind="checked:$root.selectedFieldRequired" /><br />
<!-- /ko -->
<!-- ko if: selectedFieldTypeId() == '6' --><!-- dropdown -->
<span class="span3" style="margin-left:10px;">Dimension List</span> <select data-bind="options:$root.Dimensions, value:$root.selectedDimensionId,optionsText:'Name',optionsValue:'Id'"></select><br />
<!-- /ko -->
<br /><a class="btn" style="margin-left:10px;" data-bind="click:clear">Cancel</a>
<a class="btn" data-bind="disabled:selectedFieldTypeId() != '1' && newFieldName().length>1 &&selectedSectionId()!='1',click:addField">Save</a>
</div>

It turns out that the jquery sortable/draggable functions disable the onmousedown event!
The solution I found was to disable drag/drop once one was selected, until it is saved, then re-enable drag and drop.

Related

Adding payment details to Stripe API charge call

While creating a Stripe payment I cannot seem to get the values from the rest of the form with Stripe? I have searched the docs and cannot find what they are looking for in the html to pull the form data. When I console.log the information that is pulled from the form I see null values across all of the variables.
This is a Vue application.
HTML
<template>
<form method="post" id="payment-form">
<h4 class="h4Spacing">Billing Information</h4>
<div class="form-group">
<b-form-input type="email" class="form-control" id="email" placeholder="Email Address"/>
</div>
<div class="form-group">
<b-form-input type="text" class="form-control" id="name" name="name" placeholder="Name on Card"/>
</div>
<div class="form-group">
<b-form-input type="text" class="form-control" id="address_line1" name="address_line1" placeholder="Address"/>
</div>
<div class="form-group">
<b-form-input type="text" class="form-control" id="address_city" name="address_city" placeholder="City"/>
</div>
<div class="form-group">
<b-form-input type="text" class="form-control" id="state" name="state" placeholder="State"/>
</div>
<div class="form-group">
<div id="card-element" class="form-control">
<!-- A Stripe Element will be inserted here. -->
</div>
<div v-if="successful">
<h3 class="title" data-tid="elements_examples.success.title">Payment successful</h3>
<p class="message"><span data-tid="elements_examples.success.message">Thanks for trying Stripe Elements. No money was charged, but we generated a token: </span><span class="token">tok_189gMN2eZvKYlo2CwTBv9KKh</span></p>
<a class="reset" href="#">
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path fill="#000000" d="M15,7.05492878 C10.5000495,7.55237307 7,11.3674463 7,16 C7,20.9705627 11.0294373,25 16,25 C20.9705627,25 25,20.9705627 25,16 C25,15.3627484 24.4834055,14.8461538 23.8461538,14.8461538 C23.2089022,14.8461538 22.6923077,15.3627484 22.6923077,16 C22.6923077,19.6960595 19.6960595,22.6923077 16,22.6923077 C12.3039405,22.6923077 9.30769231,19.6960595 9.30769231,16 C9.30769231,12.3039405 12.3039405,9.30769231 16,9.30769231 L16,12.0841673 C16,12.1800431 16.0275652,12.2738974 16.0794108,12.354546 C16.2287368,12.5868311 16.5380938,12.6540826 16.7703788,12.5047565 L22.3457501,8.92058924 L22.3457501,8.92058924 C22.4060014,8.88185624 22.4572275,8.83063012 22.4959605,8.7703788 C22.6452866,8.53809377 22.5780351,8.22873685 22.3457501,8.07941076 L22.3457501,8.07941076 L16.7703788,4.49524351 C16.6897301,4.44339794 16.5958758,4.41583275 16.5,4.41583275 C16.2238576,4.41583275 16,4.63969037 16,4.91583275 L16,7 L15,7 L15,7.05492878 Z M16,32 C7.163444,32 0,24.836556 0,16 C0,7.163444 7.163444,0 16,0 C24.836556,0 32,7.163444 32,16 C32,24.836556 24.836556,32 16,32 Z"></path>
</svg>
</a>
<div class="caption">
<span data-tid="elements_examples.caption.no_charge" class="no-charge">Your card won't be charged</span>
<a class="source" href="https://github.com/stripe/elements-examples/#example-1">
<svg width="16px" height="10px" viewBox="0 0 16 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M1,8 L12,8 C12.5522847,8 13,8.44771525 13,9 C13,9.55228475 12.5522847,10 12,10 L1,10 C0.44771525,10 6.76353751e-17,9.55228475 0,9 C-6.76353751e-17,8.44771525 0.44771525,8 1,8 L1,8 Z M1,4 L8,4 C8.55228475,4 9,4.44771525 9,5 C9,5.55228475 8.55228475,6 8,6 L1,6 C0.44771525,6 6.76353751e-17,5.55228475 0,5 C-6.76353751e-17,4.44771525 0.44771525,4 1,4 L1,4 Z M1,0 L15,0 C15.5522847,-1.01453063e-16 16,0.44771525 16,1 L16,1 C16,1.55228475 15.5522847,2 15,2 L1,2 C0.44771525,2 6.76353751e-17,1.55228475 0,1 L0,1 L0,1 C-6.76353751e-17,0.44771525 0.44771525,1.01453063e-16 1,0 L1,0 Z" fill="#AAB7C4"></path>
</svg>
<span data-tid="elements_examples.caption.view_source">View source on GitHub</span>
</a>
</div>
</div>
</div>
<!-- <form action="/charge" method="post" id="payment-form">-->
<!-- <div class="form-row">-->
<!-- <label for="name"> Name </label>-->
<!-- <div id="name"></div>-->
<!-- <label for="card-element">-->
<!-- Credit or debit card-->
<!-- </label>-->
<!-- <div id="card-element">-->
<!-- <!– A Stripe Element will be inserted here. –>-->
<!-- </div>-->
<!-- <!– Used to display form errors. –>-->
<!-- <div id="card-errors" role="alert"></div>-->
<!-- </div>-->
<!-- <b-button class="space" id="payment-request-button">Submit Payment</b-button>-->
<!-- </form>-->
<b-button class="space" type="submit" >Submit Payment</b-button>
</form>
</template>
Javascript for submitting form.
let form = document.getElementById('payment-form');
form.addEventListener('submit', function (event) {
console.log(event);
event.preventDefault();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
let errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
return result.token
}
}).then(function (result) {
console.log(result);
axios({
method: "POST",
url: '/api/checkout',
headers: {
Authorization: `Bearer ${authService.idToken}`,
},
data: {
subscription: result.id,
plan: this.plan
},
}).then(function (res) {
// alert("It went through! How? ")
}).catch(function (err) {
console.log(err)
});
});
});
It sounds like you'd like to pass additional field data to Stripe so that the card billing address info and other data available in the form is populated.
The createToken method that you're calling in the form submit handler can take two arguments: the card element and an optional argument containing the tokenData. https://stripe.com/docs/stripe-js/reference#stripe-create-token
You could manually refer to your form elements and pass them as tokenData like this:
var address1Input = document.getElementById('address_line1');
var addressCityInput = document.getElementById('address_city');
var stateInput = document.getElementById('state');
var nameInput = document.getElementById('name');
var tokenData = {
address_line1: address1Input.value,
address_city: addressCityInput.value,
address_state: stateInput.value,
name: nameInput.value
};
stripe.createToken(card, tokenData).then(function (result) {
//...

JSFiddle not recognizing Angular

This JSfiddle does not seem to be recognizing Angular, even though that library has been selected in the JS pane.
http://jsfiddle.net/knot22/rxqh8jtc/12/
Why isn't it working?
Code is posted below, as required by SO; however, it is probably most beneficial to navigate to the fiddle to see all the settings.
Here is the HTML:
<html ng-app="myApp">
<script src="//cdnjs.cloudflare.com/ajax/libs/validate.js/0.12.0/validate.min.js"></script>
<div ng-controller="formulaCtrlr as vm" >
<form name="vm.formContainer.form" autocomplete="off">
<div class="form-group" ng-class="{'has-error': vm.formContainer.form.FatA.$dirty && vm.formContainer.form.FatA.$invalid}">
<label for="FatA" class="col-sm-2 control-label">Fat A</label>
<input name="FatA" type="text" class="form-control col-sm-10 input-sm" ng-required="true" ng-model-options="{updateOn: 'blur'}" ui-validate="{numberCheck: 'vm.numberCheck($value)', fatRangeCheck: 'vm.fatRangeCheck($value)'}" ng-model="vm.formulaInput.Fats[0]" /><span>%</span>
<span class="error" ng-show="vm.formContainer.form.FatA.$dirty && vm.formContainer.form.FatA.$invalid">Invalid entry.</span>
<span class="error" ng-show="vm.formContainer.form.FatA.$dirty && vm.formContainer.form.FatA.$error.numberCheck">{{vm.errorMessages.numberCheck}}</span>
<span class="error" ng-show="vm.formContainer.form.FatA.$dirty && vm.formContainer.form.FatA.$error.fatRangeCheck">{{vm.errorMessages.fatRangeCheck}}</span>
</div>
<div class="form-group" ng-class="{'has-error': vm.formContainer.form.FatB.$dirty && vm.formContainer.form.FatB.$invalid}">
<label for="FatB" class="col-sm-2 control-label">Fat B</label>
<input name="FatB" type="text" class="form-control col-sm-10 input-sm" ng-required="true" ng-model-options="{updateOn: 'blur'}" ui-validate="{numberCheck: 'vm.numberCheck($value)', fatRangeCheck: 'vm.fatRangeCheck($value)'}" ng-model="vm.formulaInput.Fats[1]" /><span>%</span>
<span class="error" ng-show="vm.formContainer.form.FatB.$dirty && vm.formContainer.form.FatB.$invalid">Invalid entry.</span>
<span class="error" ng-show="vm.formContainer.form.FatB.$dirty && vm.formContainer.form.FatB.$error.numberCheck">{{vm.errorMessages.numberCheck}}</span>
<span class="error" ng-show="vm.formContainer.form.FatB.$dirty && vm.formContainer.form.FatB.$error.fatRangeCheck">{{vm.errorMessages.fatRangeCheck}}</span>
</div>
<div class="col-sm-offset-2">
<input type="reset" value="Clear" class="btn btn-default" ng-click="vm.clear()" ng-disabled="vm.formContainer.form.$pristine" />
</div>
</form>
<div>formula input: {{vm.formulaInput}}</div>
</div>
</html>
Here is the JS:
angular.module('myApp', ['ui.validate'])
.controller("formulaCtrlr", ['$scope', function ($scope) {
var vm = this;
vm.formContainer = {
form: {}
}
var originalFormContainer = angular.copy(vm.formContainer); //used for clear function below (to clear form)
vm.formulaInput = {};
vm.formulaInput.Fats = [];
vm.clear = function () {
//vm.formulaInput.Fats = [];
//vm.formContainer.form.$setPristine();
vm.formContainer = angular.copy(originalFormContainer);
}
vm.errorMessages = {
numberCheck: 'Value must be a number.',
fatRangeCheck: 'Number must be between 0 and 100.'
}
vm.numberCheck = function (value) {
var result = !(isNaN(parseFloat(value)));
return result;
//return !(isNaN(parseFloat(value)));
}
vm.fatRangeCheck = function (value) {
var result = (value && value > 0.0 && value < 100.0);
return result;
//return (value && value > 0.0 && value < 100.0);
}
}]);
After adding
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-validate/1.2.3/validate.min.js"></script> to the HTML it worked.

how to change value of v-if condition of current item in loop (on click)

In my Vue.js app, I have a list of contacts in a v-for loop, each with a corresponding 'edit' button; I want to toggle the v-if="="!isEditingContact" condition for only the selected contact. I have the index of the button/contact to be edited, but I don't know how to toggle the 'isEditingContact' condition for the selected contact.
My component:
<template>
<div class="container" id="project-edit">
<section class="client-data">
<!-- show static if editMode FALSE -->
<dl v-if="!isEditingClient">
<!-- SNIP-->
</dl>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="isEditingClient">
<!-- SNIP -->
</fieldset>
<div class="buttons">
<button v-if=!isEditingClient id="edit-client" v-on:click="editMode">edit</button>
<button v-if=isEditingClient v-on:click="cancelEdit">cancel</button>
<button v-if=isEditingClient v-on:click="post">save changes</button>
</div>
</section><!-- END .client-data -->
<section class="gig-data">
<!-- show static if editMode FALSE -->
<dl v-if="!isEditingGig">
<!-- SNIP-->
</dl>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="isEditingGig">
<!-- SNIP-->
</fieldset>
<div class="buttons">
<button v-if=!isEditingGig id="edit-gig" v-on:click="editMode">edit</button>
<button v-if=isEditingGig v-on:click="cancelEdit">cancel</button>
<button v-if=isEditingGig v-on:click="post">save changes</button>
</div>
</section><!-- END .gig-data -->
<section class="contacts-wrapper">
<!-- show static if editMode FALSE -->
<dl>
<dt>contacts:</dt>
<dd>
<ul class="contacts">
<li v-if="!isEditingContact" v-for="(contact, ix) in project.contacts" v-bind:key="??">
{{ contact.name }}<br />
{{ contact.title }}<br />
{{ contact.email }}<br />
{{ contact.phone }}
<div class="buttons">
<button v-if=!isEditingContact id="edit-contact" v-on:click="editContact(contact, ix)">edit</button>
<button v-if=isEditingContact v-on:click="cancelEdit">cancel</button>
<button v-if=isEditingContact v-on:click="post">save changes</button>
</div>
</li>
</ul>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="isEditingContact">
<!--
SNIP:
FORM TO BE DISPLAYED IN PLACE OF THE SELECTED CONTACT,
AND W/OUT HIDING OTHER CONTACTS
-->
</fieldset>
</dd>
</dl>
</section>
</div>
</template>
<script>
export default {
props: [ "projectID" ],
components: {
},
data () {
return {
id: this.$route.params.id,
title: "Edit Project",
subtitle: "ID: " + this.$route.params.id,
project: {},
contactInfo: {},
workLocation: true,
submitted: false,
isEditingClient: false,
isEditingGig: false,
isEditingContact: false
}
}, // data
created: function() {
this.$http.get("https://xyz.dataworld.com/projects/" + this.id + ".json")
.then(function(data) {
return data.json();
}).then(function(data) {
this.project = data;
})
}, // created
methods: {
addContactInfo: function(e) {
e.preventDefault();
this.projectID = this.id;
this.project.contacts.push(this.contactInfo);
this.contactInfo = {};
},
editMode: function(e) {
const buttonID = e.currentTarget.id;
switch (buttonID) {
case "edit-client":
this.isEditingClient = !this.isEditingClient;
break;
case "edit-gig":
this.isEditingGig = !this.isEditingGig;
break;
// case "edit-contact": ... this is uselesss, since it would hide all contacts as it shows the form
// this.isEditingContact = !this.isEditingContact;
// break;
default:
}
},
editContact: function(e) {
},
cancelEdit: function() {
this.isEditingClient = false;
this.isEditingGig = false;
this.isEditingContacts = false;
},
post: function() {
console.log(this.project);
this.$http.post("https://sr-giglog.firebaseio.com/projects.json", this.project)
.then(function(data){
this.submitted = true;
}
)} // post function
} // methods
}
</script>
Most commonly this is done by adding a flag to the individual objects in your list. In this case, an editing flag, or whatever you want to call it. You would initialize it with false. You can add this flag either server side or client side. If you want to do it client side it would look something like this:
this.$http.get("https://xyz.dataworld.com/projects/" + this.id + ".json")
.then(data => data.json())
.then(data => {
// add the editing property
for (let contact of data.contacts)
this.$set(contact, 'editing', false)
this.project = data
})
Then, use that property in your template.
<section class="contacts-wrapper">
<!-- show static if editMode FALSE -->
<dl>
<dt>contacts:</dt>
<dd>
<ul class="contacts">
<li v-if="!contact.editing" v-for="(contact, ix) in project.contacts" v-bind:key="??">
{{ contact.name }}<br />
{{ contact.title }}<br />
{{ contact.email }}<br />
{{ contact.phone }}
<div class="buttons">
<button v-if="!contact.editing" id="edit-contact" v-on:click="contact.editing = true">edit</button>
<button v-if="contact.editing" v-on:click="contact.editing = false">cancel</button>
<button v-if="contact.editing" v-on:click="post">save changes</button>
</div>
</li>
</ul>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="contact.edting">
...
</fieldset>
</dd>
</dl>
</section>
You can store editing contact's id and check that inside v-if.
If you stored the id of contact that is being edited in editingContactId then you can modify your code to this:
<ul class="contacts">
<li v-for="(contact, ix) in project.contacts" v-bind:key="??">
{{ contact.name }}<br />
{{ contact.title }}<br />
{{ contact.email }}<br />
{{ contact.phone }}
<div class="buttons">
<button v-if="editingContactId!=contact.id" id="edit-contact" v-on:click="editContact(contact, ix)">edit</button>
<button v-if="editingContactId==contact.id" v-on:click="cancelEdit">cancel</button>
<button v-if="editingContactId==contact.id" v-on:click="post">save changes</button>
</div>
</li>
</ul>
If it helps anyone, here's my revised, working solution (at least this reflects specifically what I was asking to achieve in my OP):
My component:
<template>
<div class="container" id="project-edit">
<section class="client-data">
<!-- show static if editMode FALSE -->
<dl v-if="!isEditingClient">
<!-- SNIP-->
</dl>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="isEditingClient">
<!-- SNIP -->
</fieldset>
<div class="buttons">
<button v-if=!isEditingClient id="edit-client" v-on:click="editMode">edit</button>
<button v-if=isEditingClient v-on:click="cancelEdit">cancel</button>
<button v-if=isEditingClient v-on:click="post">save changes</button>
</div>
</section><!-- END .client-data -->
<section class="gig-data">
<!-- show static if editMode FALSE -->
<dl v-if="!isEditingGig">
<!-- SNIP-->
</dl>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="isEditingGig">
<!-- SNIP-->
</fieldset>
<div class="buttons">
<button v-if=!isEditingGig id="edit-gig" v-on:click="editMode">edit</button>
<button v-if=isEditingGig v-on:click="cancelEdit">cancel</button>
<button v-if=isEditingGig v-on:click="post">save changes</button>
</div>
</section><!-- END .gig-data -->
<section class="contacts-wrapper">
<!-- show static if editMode FALSE -->
<dl>
<dt>contacts:</dt>
<dd>
<li v-for="(contact, ix) in project.contacts">
<!-- show orig data if editMode FALSE -->
<div v-if="!contact.editingContact">
{{ contact.name }} ({{ ix }})<br />
{{ contact.title }}<br />
{{ contact.email }}<br />
{{ contact.phone }}
<div class="buttons">
<button v-if=!contact.editingContact id="edit-contact" v-on:click="contact.editingContact = true">edit</button>
</div>
</div>
<!-- show FORM if editMode TRUE -->
<fieldset v-if="contact.editingContact">
<!-- SNIP: FORM ... -->
<div class="buttons">
<!-- I realize that the v-if attributes are not necessary here -->
<button v-if=contact.editingContact v-on:click="contact.editingContact = false">cancel</button>
<button v-if=contact.editingContact v-on:click="post">save changes</button>
</div>
</fieldset>
</li>
</dd>
</dl>
</section>
</div>
</template>
<script>
export default {
props: [ "projectID" ],
components: {
},
data () {
return {
id: this.$route.params.id,
title: "Edit Project",
subtitle: "ID: " + this.$route.params.id,
project: {},
contactInfo: {},
workLocation: true,
submitted: false,
isEditingClient: false,
isEditingGig: false,
}
}, // data
created: function() {
this.$http.get("https://xyz.dataworld.com/projects/" + this.id + ".json")
.then(data => data.json())
.then(data => {
for (let contact of data.contacts) {
this.$set(contact, 'editingContact', false)
}
this.project = data;
})
}, // created
methods: {
addContactInfo: function(e) {
e.preventDefault();
this.projectID = this.id;
this.project.contacts.push(this.contactInfo);
this.contactInfo = {};
},
editMode: function(e) {
const buttonID = e.currentTarget.id;
switch (buttonID) {
case "edit-client":
this.isEditingClient = !this.isEditingClient;
break;
case "edit-gig":
this.isEditingGig = !this.isEditingGig;
break;
default:
}
},
editContact: function(e) {
},
cancelEdit: function() {
this.isEditingClient = false;
this.isEditingGig = false;
},
post: function() {
console.log(this.project);
this.$http.post("https://sr-giglog.firebaseio.com/projects.json", this.project)
.then(function(data){
this.submitted = true;
}
)} // post function
} // methods
}
</script>
Now, if you'd all just stand by while I prepare my next twelve questions ...

Selenuim/Protractor can't find or click in textbox

I have a code from a website as follows and I want to use the 5th line from code segment below <input type="text" placeholder="Enter Workflow Name"
Code
<div class="workflow-container ng-scope" data-ng-controller="sourceCode.Designer.uiComponents.conciergeScreen.templates.NewWorkflowController">
<div class="input">
<div class="wrapper top" data-ng-class="{'fill': hosted === true}">
<label class="welcome">What should your workflow be called?</label>
<input type="text" placeholder="Enter Workflow Name" class="workflow-name-textbox ng-valid ng-not-empty ng-touched ng-dirty ng-valid-parse" data-ng-class="{'error': errors.error}" autofocus="" data-ng-focus="select($event)" data-ng-model="conciergetitle" data-ng-model-options="{ updateOn: 'default blur', debounce: { default: 300, blur: 300 } }" data-ng-change="inputchange(designeritems)" data-ng-keyup="$event.keyCode == 13 && createnewstudioitem(designerItems[0], conciergetitle, $event)" style="">
<div class="errogory">
<div class="summary">
<!-- ngIf: errors.error || errors.category -->
</div>
<div class="category" data-ng-click="categorypicker($event)">
<label>Folder</label>
<i class="icon icon-set-assetbrowser icon-size16 ic-categoryserver"></i>
Workflow
</div>
</div>
<div class="concierge-button-grid">
<div class="concierge-button-container">
<button id="createWorkflow" data-button-error="false" class="concierge-button button-command" data-ng-disabled="!newWorkflowReady" data-ng-class="{ 'error': errors.button, 'is-disabled error' : errors.button }" data-ng-click="createnewstudioitem(designerItems[0], conciergetitle, $event)" disabled="disabled">
<!-- ngIf: !errors.button --><span data-ng-bind="getString('new_workflow_create_button')" data-ng-if="!errors.button" class="ng-binding ng-scope">Create</span><!-- end ngIf: !errors.button -->
<!-- ngIf: errors.button -->
</button>
</div>
<div class="concierge-button-container">
<button id="discardWorkflow" class="concierge-button concierge-button-discard button-command tertiary" data-ng-click="discard()">
<span data-ng-bind="getString('discard_workflow_button')" class="ng-binding">Discard</span>
</button>
</div>
</div>
</div>
<!-- ngIf: showrecent -->
<!-- ngIf: showrecent -->
</div>
I want to click in the textbox so that I can clear the text. I have tried the following:
describe("New Screen", function () {
it("Should give textbox a new name", function () {
browser.sleep(10000);
console.log('Enter new name');
var editName = element.all(by.className('.workflow-name-textbox'));
editName.first().click().then(function () {
console.log('Clicked on Create');
})
browser.sleep(10000);
})
I get a error: Index out of bound. Trying to access element at index: 0 ...
if I change my code above to:
var editName = element.all(by.css('.workflow-name-textbox'));
editName.click().then(function () {
console.log('Clicked on Create');
I dont get errors but I dont see any clicking going on.
I know my protractor works because I have navigated to this page using similar code.
Do anyone have suggestions what else I could try.
I had to go two iFrames down:
//Parent
browser.switchTo().frame('Iframe1');
//Child
browser.switchTo().frame('Iframe2');
//var NewTextBox = browser.findElement(by.css('.name-textbox')).clear();
var NewTextBox = element.all(by.css('.name-textbox'));
NewTextBox.clear().then(function () {
console.log('Clear text');
Did you tried this way instead of element.all.
element.all return a list elemenet and element return only single element.
var NewTextBox = element(by.css('.workflow-name-textbox'));
or
var NewTextBox = element(by.xpath('//input[#placeholder='Enter Workflow Name']'));

How to give validation to each text box which should take only one character or digit using asp.net mvc 4

I am new to asp .net mvc 4.
I am doing a validation for a pan card page.
I want to do ,only one character can able to insert for first 5 text box then only one number to next 4 text box and last text box should accept only one character.
#using (Html.BeginForm())
{
<input type="text" pattern="[A-Z]{1}" style="background-color:cyan; height:20px;width:20px;" name="txt1st" id="txt1st" required />
<input type="text" pattern="[A-Z]{1}" style="background-color:cyan; height:20px;width:20px;" name="txt2nd" id="txt2nd" required />
<input type="text" pattern="[A-Z]" style="background-color:cyan; height:20px;width:20px;" name="txt3rd" id="txt3rd" required />
<input type="text" pattern="[A-Z]" style="background-color:wheat; height:20px;width:20px;" readonly value="P" name="txt4th" id="txt4th" />
<input type="text" pattern="[A-Z]" style="background-color:cyan; height:20px;width:20px;" name="txt5th" id="txt5th" required />
<input type="text" pattern="[0-9]" style="background-color:blue; color:wheat;height:20px;width:20px;" name="int6th" id="int6th" required />
<input type="text" pattern="[0-9]" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int7th" id="int7th" required />
<input type="text" pattern="[0-9]" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int8th" id="int8th" required />
<input type="text" pattern="[0-9]" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int9th" id="int9th" required />
<input type="text" pattern="[A-Z]" style="background-color:cyan; height:20px;width:20px;" name="txt10th" id="txt10th" required /><br />
<input type="submit" class="btnPrimary" value="Update" />
}
I am not getting how to do this and how to give validation to each text box ,I shouldn't able to enter second value in the textbox.
Can anyone tell me how to solve this ?
I have done like this...
#using (Html.BeginForm())
{
<input type="text" class="letter" style="background-color:cyan; height:20px;width:20px;" name="txt1st" id="txt1st" required />
<input type="text" class="letter" style="background-color:cyan; height:20px;width:20px;" name="txt2nd" id="txt2nd" required />
<input type="text" class="letter" style="background-color:cyan; height:20px;width:20px;" name="txt3rd" id="txt3rd" required />
<input type="text" class="letter" style="background-color:wheat; height:20px;width:20px;" readonly value="P" name="txt4th" id="txt4th" />
<input type="text" class="letter" style="background-color:cyan; height:20px;width:20px;" name="txt5th" id="txt5th" required />
<input type="text" class="number" style="background-color:blue; color:wheat;height:20px;width:20px;" name="int6th" id="int6th" required />
<input type="text" pattern="[0-9]" class="number" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int7th" id="int7th" required />
<input type="text" pattern="[0-9]" class="number" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int8th" id="int8th" required />
<input type="text" pattern="[0-9]" class="number" style="background-color: blue; color: wheat; height: 20px; width: 20px;" name="int9th" id="int9th" required />
<input type="text" pattern="[A-Z]" class="letter" style="background-color:cyan; height:20px;width:20px;" name="txt10th" id="txt10th" required /><br />
<input type="submit" class="btnPrimary" value="Update" />
}
<script>
$(document).ready(function () {
$('.letter').keyup(function (e) {
if (this.value != 'A' && this.value != 'B' && this.value != 'C'
&& this.value != 'D' && this.value != 'E' && this.value != 'F'
&& this.value != 'G'&& this.value != 'H'&& this.value != 'I'
&& this.value != 'J'&& this.value != 'K'&& this.value != 'L'
&& this.value != 'M'&& this.value != 'N'&& this.value != 'O'
&& this.value != 'P'&& this.value != 'Q'&& this.value != 'R'
&& this.value != 'S' && this.value != 'T' && this.value != 'U'
&& this.value != 'V' && this.value != 'W' && this.value != 'X'
&& this.value != 'Y'&& this.value != 'Z'){
this.value = '';
}
});
$('.number').keyup(function (e) {
if (this.value != '1' && this.value != '2' && this.value != '3'
&& this.value != '4' && this.value != '5' && this.value != '6'
&& this.value != '7' && this.value != '8' && this.value != '9' && this.value != '0')
{
this.value = '';
}
});
});
It seems you are not at all using what MVC provides.
1. Create a model according to your requirement like,
public class PANCardDetails
{
[RegularExpression("Your regyular expr. to validate")]
public string Number1 { get; set; }
// Do define the other properties like the above
}
Modify your form in your view with the model as,
#model PANCardDetails
#using (Html.BeginForm())
{
Html.EnableClientValidation(true);
Html.EnableUnobtrusiveJavaScript(true);
#Html.TextBoxFor(pancardDetails=>pancardDetails.Number1)
#Html.ValidationMessageFor(pancardDetails=>pancardDetails.Number1)
//Similarly create the controls for other properties too
}
Include the jquery, jquery unobtrusive and jquery validate files to enable client side validation and the MVC will do the rest in validating.
Your can Use this also
<asp:TextBox ID="txtName" runat="server"/>
<asp:RegularExpressionValidator ID="revName" runat="server" ErrorMessage="Enter Your Name" ControlToValidate="txtName" ValidationExpression="[a-zA-Z]{1}" />
For number input use ValidationExpression="[0-9]{1}"