HTML code:
<div class="col-sm-9">
<input name="NewCardOrAccountNumber" class="form-control ui-autocomplete-input" id="NewCardOrAccountNumber" type="text" value="" autocomplete="off">
<span class="ui-helper-hidden-accessible" role="status" aria-live="polite"></span>
</div>
<div class="unvisible" id="clientInfoNew">
<div class="form-group">
<label class="col-sm-3 control-label">FIRST NAME</label>
<div class="col-sm-9" id="FnameNew"></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">LAST NAME</label>
<div class="col-sm-9" id="LnameNew"></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">BIRTH DATE</label>
<div class="col-sm-9" id="BirthDateNew"></div>
</div>
Watin code:
[TestMethod]
[TestCategory("Rimi Change card page")]
public void Rimi_4444_Change_Card_and_Assert()
{
//Web Address
using (IE ie = new IE(this.Rimi))
{
//IE ie = new IE(RimiChangeCard);
ie.BringToFront();
ie.ShowWindow(WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle.Maximize);
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
If I write card number from keyboard, the invisible class appear, and you can see FIRST NAME, LAST NAME and so on. But if I do this with watin, it does not appear, and you only see card number which you input. Its like hidden fields of information. I do not know how to make that I could see this fields when I input card number.
There would be a JavaScript function, which gets executed when you manually enter the data in the text field.Go through the Java Script functions on the same page which refer to that element using it's ID NewCardOrAccountNumber.
Refer to this link for sample application. Where msg_to is element, and has a KeyUp event associated. When that filed gets a , value, there is a div section inside which a `Subject' field is shown.
Similarly, after executing the TypeText, try to trigger related event mentioned in the Java Script event using Java script execution.
EDIT: I see that the javascript functions gets executed after bulr event is fired. This means the textbox field should loose the focus. Try the below options.
// 1. Try focusing out of control.
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
ie.TextField(Find.ById("OldCardOrAccountNumber")).Click();
ie.WaitForComplete();
// 2. Try Using Send Keys method to tab out.
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
System.Windows.Forms.SendKeys.SnedWait("{TAB}"); // Need to add System.Windows.Forms reference to the project.
I put image on the internet, so click on this link Image and you will see on first image how look page, second picture - what have to happen when you input card number (from keyboard), third - what happen when card namuber is input from watin (does not appear information about card).
HTML code:
<div class="ibox-content">
<br>
<div class="form-horizontal">
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label class="col-sm-3 control-label">NEW CARD</label>
<input name="NewCardId" id="NewCardId" type="hidden" value="0" data-val-required="The NewCardId field is required." data-val-number="The field NewCardId must be a number." data-val="true">
<div class="col-sm-9"><span class="ui-helper-hidden-accessible" role="status" aria-live="polite"></span><input name="NewCardOrAccountNumber" class="form-control ui-autocomplete-input" id="NewCardOrAccountNumber" type="text" value="" autocomplete="off"></div>
</div>
<div class="unvisible" id="clientInfoNew">
<div class="form-group">
<label class="col-sm-3 control-label">FIRST NAME</label>
I maybe find what you looking for Sham, but I do not know how to use it :
<script type="text/javascript">
$(document).ready(function() {
var NewCardId = "#NewCardId";
var OldCardId = "#OldCardId";
var NewCardNumber = "#NewCardOrAccountNumber";
var OldCardNumber = "#OldCardOrAccountNumber";
$(NewCardNumber).autocomplete(
{
source: function(request, response) {
$.ajax({
url: '/LoyaltyWebApplication/Suggestion/GetCardSuggestions',
dataType: "json",
data: {
str: $(NewCardNumber).val()
},
success: function(data) {
response($.map(data, function(item) {
var label = "";
if (item.Fname != null) label += item.Fname;
if (item.Lname != null) label += " " + item.Lname;
if (label.trim() != '') label = " (" + label.trim() + ")";
return {
value: item.CardNumber,
label: item.CardNumber + label
}
}));
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
},
select: function(event, ui) {
getCardDetails($(NewCardNumber), $(NewCardId), 'newCardSegments', true);
$("#newCardSegments").hide();
$("#clientInfoNew").show();
},
minLength: 2
}).blur(function() {
getCardDetails($(NewCardNumber), $(NewCardId), 'newCardSegments', true);
});
$(OldCardNumber).autocomplete(
{
source: function(request, response) {
$.ajax({
url: '/LoyaltyWebApplication/Suggestion/GetCardSuggestions',
dataType: "json",
data: {
str: $(OldCardNumber).val()
},
success: function(data) {
response($.map(data, function(item) {
var label = "";
if (item.Fname != null) label += item.Fname;
if (item.Lname != null) label += " " + item.Lname;
if (label.trim() != '') label = " (" + label.trim() + ")";
return {
value: item.CardNumber,
label: item.CardNumber + label
}
}));
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
},
select: function(event, ui) {
getCardDetails($(OldCardNumber), $(OldCardId), 'oldCardSegments', false);
$("#oldCardSegments").hide();
},
minLength: 2
}).blur(function() {
getCardDetails($(OldCardNumber), $(OldCardId), 'oldCardSegments', false);
});
function getCardDetails(cardNumHolder, cardIdHolder, segmentTablePlace, isNew) {
$.getJSON('/LoyaltyWebApplication/LOV/SetId?lovType=ReplacementLOV&lovValue=' + cardNumHolder.val(), null,
function(data) {
$("#clientInfo" + ((isNew) ? "New" : "Old")).show();
if (cardNumHolder.val() == '') {
return;
}
var i;
for (i = 0; i < data.otherNames.length; i++) {
$("#" + data.otherValues[i] + (isNew ? "New" : "Old")).text(data.otherNames[i]);
}
cardIdHolder.val(data.Id);
$.getJSON('/LoyaltyWebApplication/Replacement/ClientSegmentsList?clientId=' + data.Id + "&no_cache=" + Math.random, function(data) {
$("#" + segmentTablePlace).find('tbody').empty();
if (data.length > 0) {
$.each(data, function(index) {
$("#" + segmentTablePlace).find('tbody').append("<tr><td>" + data[index].SegmentCode + "</td><td>" + data[index].SegmentName + "</td></tr>");
});
$("#" + segmentTablePlace).show();
}
});
});
}
$("#resetVal").click(function() {
$("#NewCardOrAccountNumber").attr("value", "");
$("#NewCardOrAccountNumber").val("");
$("#NewCardId").attr("value", "");
$("#NewCardId").val("");
$("#clientInfoNew").hide();
$("#OldCardOrAccountNumber").attr("value", "");
$("#OldCardOrAccountNumber").val("");
$("#OldCardId").attr("value", "");
$("#OldCardId").val("");
$("#clientInfoOld").hide();
return false;
});
});
</script>
Related
UserAdmin.cshtml
<div class="modal-body">
<form id="upload-file-dialog-form"
class="needs-validation form-group" novalidate
onsubmit="UploadFile()"
enctype="multipart/form-data"
method="post">
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="file_Uploader" />
</div>
<div class="form-group">
<div class="col-md-10 modal-footer">
<input type="submit" class="btn btn-primary" value="Upload"/>
</div>
</div>
</form>
</div>
UserAdmin.js
function UploadFile() {
var form = $('form')[0];
var formData = new FormData(form);
console.log(formData);
$.ajax({
url: '/API/Upload',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function (data) {
},
error: function () {
}
});
}
Controller
[HttpPost]
public async Task<IActionResult> Upload(List<IFileUpload> files)
{
try
{
var check = (HttpContext.Request.Form.Files);
long size = files.Sum(f => f.Length);
//some code removed
return Ok(new { count = files.Count, size, filePaths });
}
catch (Exception exc)
{
logger.Error("Error in upload() " + exc.Message);
throw;
}
}
the files in controller is always 0.
If onsubmit="UploadFile()" is replaced with
asp-controller="API" asp-action="Upload"
then I get something in check but again converting it to List of IFileUpload is another blocker
First of all, If you want to upload multiple files you have to add multiple="multiple" in your input. FormData will be empty if you print it like this, you have to iterate through the items.
<input type="file" name="file_Uploader" multiple="multiple" />
Please follow the codes below, I tested it working.
Complete form
<form id="upload-file-dialog-form"
onsubmit="UploadFile(event)">
<div class="col-md-10">
<p>Upload one or more files using this form:</p>
<input type="file" name="file_Uploader" multiple="multiple" />
</div>
<div class="form-group">
<div class="col-md-10 modal-footer">
<input type="submit" class="btn btn-primary" value="Upload" />
</div>
</div>
</form>
Construct form data like below
<script>
function UploadFile(e) {
e.preventDefault();
var formData = new FormData($('#upload-file-dialog-form')[0]);
$.each($("input[type='file']")[0].files, function(i, file) {
formData.append('files', file);
});
$.ajax({
url: '/API/Upload',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(data) {
},
error: function() {
}
});
}
</script>
Action method
[HttpPost]
public async Task<IActionResult> Upload(List<IFormFile> files)
{
try
{
var check = (HttpContext.Request.Form.Files);
long size = files.Sum(f => f.Length);
return Ok(new { count = files.Count, size });
}
catch (Exception exc)
{
_logger.LogWarning("Error in upload() " + exc.Message);
throw;
}
}
In model class, use IFormFile
public List<IFormFile> file_Uploader {get;set;}"
In controller, change the parameter like this
public async Task<IActionResult> Upload(List<IFormFile> file_Uploader)
add multiple to upload more files, and keep the name attribute the same as parameter to post value, code like below:
<input type="file" name="file_Uploader" multiple/>
result:
In my SharePoint page, I have a single selection dropdown DP that is linked to a multi-selection dropdown Category. The values of Category are appended when DP is selected. I want to change DP to multi-selection and still have Category linked to it so that the values of Category will be added-on if more than one DP is selected. How can I do this?
<body>
<div class="form-group">
<label>DP</label>
<select class="form-control select2" id="sp_DP" multiple>
</select>
</div>
<div class="form-group">
<label>Category</label>
<select class="form-control select2" id="spCategory" multiple>
</select>
</div>
</body>
<script>
$('[id*="sp_DP"]').on('change', function()
{
//$('#spCategory').empty();
var dpName = $(this).find("option:selected").text();
AddCategories(dpName);
});
function LoadDPOptions()
{
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('DP')/items?$select=ID,Title&$orderby=Title asc&$top=200",
headers: {
Accept: "application/json;odata=verbose"
},
async: false,
success: function(data) {
if (data.d.results.length > 0)
{
$('[id*="sp_DP"]').append($("<option></option>").attr("value", 0).text(""));
for (var i = 0; i < data.d.results.length; i++)
{
var item = data.d.results[i];
$('[id*="sp_DP"]').append($("<option></option>").attr("value", item .ID).text(item.Title));
}
}
},
error: function(data) {
console.log("An error occurred. Please try again.");
}
});
}
function AddCategories(dpName)
{
if(dpName)
{
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('DP')/items?$select=ID,Title,Category/ID,Category/Title&$expand=Category&$filter=Title eq " + encodeURIComponent("'" + dpName + "'"),
headers: {
Accept: "application/json;odata=verbose"
},
async: false,
success: function(data) {
if (data.d.results.length > 0)
{
var item = data.d.results[0];
var catsArr = item.Category["results"];
catsArr.sort(function(a, b) {
var t1 = a.Title.toUpperCase();
var t2 = b.Title.toUpperCase();
return (t1 < t2 ) ? -1 : (t1 > t2 ) ? 1 : 0;
});
for(var i = 0; i < catsArr.length; i++)
{
var result = catsArr[i];
$('#spCategory').append($("<option></option>").attr("value", result.ID).text(result.Title));
}
}
},
error: function(data) {
console.log("An error occurred. Please try again.");
}
});
}
}
</script>
I am attempting to provide user friendly input (as a percentage) for a decimal and be able to validate. I am stuck because the asp-validation-for will not display if the associated input is hidden.
Current technique is to use autonumeric.js for the client side formatting on a display only field that gets copied into the field to be saved to db.
How can I get validation message to display?
LoanEstimate.cs
[NotMapped]
public string RateDisplayOnly { get; set; }
[Range(0,1,ErrorMessage="Rate must be between 0.000% and 100.00%")]
[DisplayFormat(DataFormatString = "{0:p}")]
[Required]
public decimal? Rate { get; set; }
Create.cshtml
<div class="form-group">
<label asp-for="LoanEstimate.Rate" class="control-label"></label>
<input asp-for="LoanEstimate.RateDisplayOnly" class="form-control autonumeric-display-only autonumeric-percent" />
<input asp-for="LoanEstimate.Rate" class="form-control" type="hidden"/>
<span asp-validation-for="LoanEstimate.Rate" class="text-danger"></span>
</div>
Javascript
$(document).ready(function ($) {
//autonumeric.js field formatting
const anElement = AutoNumeric.multiple('.autonumeric-currency', {
currencySymbol: "$"
});
const anElement2 = AutoNumeric.multiple('.autonumeric-percent', {
decimalPlaces: 3,
rawValueDivisor: 100,
suffixText: "%"
}
)
$(".autonumeric-display-only").on('keyup', function () {
var str = this.id
var getThis = str.substring(0, str.indexOf("DisplayOnly"))
$("#" + getThis).val(AutoNumeric.getNumericString("#" + this.id));
});
});
ProblemValidation message does not display when input for LoanEstimate.Rate is hidden
Note: here is it displaying properly when not hidden
Use $.validator.setDefaults,here is a demo:
View:
<form method="post">
<div class="form-group">
<label asp-for="Rate" class="control-label"></label>
<input asp-for="RateDisplayOnly" class="form-control autonumeric-display-only autonumeric-percent" onblur="validateRate()"/>
<input asp-for="Rate" class="form-control" hidden />
<span asp-validation-for="Rate" class="text-danger"></span>
</div>
<input type="submit" value="submit" />
</form>
js:
function validateRate() {
$("#Rate").valid();
}
$.validator.setDefaults({
ignore: [],
// other default options
});
$(document).ready(function ($) {
//autonumeric.js field formatting
const anElement = AutoNumeric.multiple('.autonumeric-currency', {
currencySymbol: "$"
});
const anElement2 = AutoNumeric.multiple('.autonumeric-percent', {
decimalPlaces: 3,
rawValueDivisor: 100,
suffixText: "%"
}
)
$(".autonumeric-display-only").on('keyup', function () {
var str = this.id
var getThis = str.substring(0, str.indexOf("DisplayOnly"))
$("#" + getThis).val(AutoNumeric.getNumericString("#" + this.id));
});
});
result:
I have a page which I validate the email add input #blur. This works perfectly and displays the error message if it fails validation rules set but the issue I have is that due to the #blur, when I click my reset button the error quickly displays then hides and this is poor UI and I want to stop it but can't figure out how to.
HTML
<div class="card" v-on:click="select($event)">
<div class="card-body">
<div class="form-group row">
<label class="col-sm-3 col-form-label pr-0" for="emailAddField">Email <span class="text-danger">*</span></label>
<div class="col-sm-9">
<div class="input-group">
<input id="emailAddField" ref="pdEmailAdd" class="form-control" type="search" :value="pdEmailAdd" #input="pdEmailAddInput" #blur="emailInputValChecker($event)" placeholder="Enter an email address">
<div class="input-group-append" :class="emailButtonValidation">
<a class="btn input-group-text primaryBtn" :class="emailButtonValidation" type="button" :href="'mailto:' + pdEmailAdd">
<i class="far fa-envelope"></i>
</a>
</div>
</div>
<div v-if="emailFormatErrorMsg" class="text-danger">Incorrect email address format</div>
</div>
<div class="card-footer">
<button id="resetButton" ref="resetButton" class="btn btn-warning col-4" #click="pdInitPageStates($event)" :disabled="resetDetails">
Reset details
</button>
</div>
</div>
I have 'hacked' at the card trying to use #click on the card to get the id but this didn't work so I set the id in my `data but not happy about it and sure there is a lot better way but I just can't figure it out
Code
data() {
return {
pdEmailAdd: '',
reg: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,24}))$/,
detailsChanged: false,
emailIncorrectFormat: false,
targetId: 'resetButton', // HACK
targetId2: '', // HACK
}
},
computed: {
emailButtonValidation() {
if (!this.pdEmailAdd || !this.reg.test(this.pdEmailAdd)) {
if (this.pdEmailAdd === '') {
this.emailIncorrectFormat = false;
} else {
this.emailIncorrectFormat = true;
}
return 'disabled'
} else {
this.emailIncorrectFormat = false;
return ''
}
},
resetDetails() {
this.detailsChanged = false;
if (this.pdName != this.$store.state.account.firstname + ' ' + this.$store.state.account.lastname) {
this.detailsChanged = true;
}
if (this.telNoType === 'ddi' && this.pdTelNo != this.$store.state.account.ddi) {
this.detailsChanged = true;
} else if (this.telNoType === 'mobile' && this.pdTelNo != this.$store.state.account.mobile) {
this.detailsChanged = true;
} else if (this.telNoType === 'na' && this.pdTelNo != '') {
this.detailsChanged = true;
}
if (this.pdExtNo != this.$store.state.account.extension) {
this.detailsChanged = true;
}
if (this.pdEmailAdd != this.$store.state.user.adminemail) {
this.detailsChanged = true;
}
return !this.detailsChanged;
}
}
// Another hack to try set it soon as page loads
mounted() {
this.$refs.resetButton.click();
},
methods: {
emailInputValChecker(event) {
this.emailFormatErrorMsg = false;
if (!this.pdEmailAdd || !this.reg.test(this.pdEmailAdd)) {
if (this.pdEmailAdd === '') {
this.emailFormatErrorMsg = false;
} else {
this.select(event)
// Uses the 'dirty hacks'
if (this.targetId !== '' && this.targetId !== 'resetButton' && this.targetId2 !== 'resetButton') {
this.emailFormatErrorMsg = true;
};
}
}
},
select(event) {
this.targetId = event.target.id;
if (this.targetId === 'resetButton') {
this.targetId2 === 'resetButton';
} else if (this.targetId === '') {
this.targetId === 'resetButton';
}
}
}
Basically all I want is the input to check it passes validation when input is left unless the reset button is clicked then ignore it but think I've gone code blind and can't think of a way to do this.
The mousedown event on your reset button is what causes blur on the input to fire. Adding #mousedown.prevent to the reset button will stop that from happening specifically when the reset button is clicked.
This snippet ought to illustrate the solution. Remove #mousedown.prevent from the reset button and you'll see similar behavior to your issue, with the error briefly flashing.
new Vue({
el: '#app',
data: {
email: '',
error: null
},
methods: {
onBlur () {
if (this.email === 'bad') {
this.error = 'bad email!'
} else {
this.error = null
}
},
onReset () {
this.error = null
this.email = ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="onReset" #mousedown.prevent>Reset</button>
<p>
Type in "bad" and leave input to trigger validation error<br>
<input type="text" v-model="email" #blur="onBlur"/>
</p>
<p>{{ email }}</p>
<p v-if="error">error!</p>
</div>
I have a basic file upload in Vue.js. I am trying to append a textarea so that I can add a description about the file. However, I can not see to get this to work. The idea is to be able to send files through the API that i am creating in laravel.
<template>
<div class="container">
Files
<input type="file" id="files" ref="files" multiple v-on:change="handleFilesUpload()" />
<div v-for="(file, key) in files" :key="file.id" class="file-listing">
{{ file.name }}
<textarea
name="description"
id="description"
cols="30"
rows="10"
v-model="description"
></textarea>
<span class="remove-file" v-on:click="removeFile( key )">Remove</span>
</div>
<button v-on:click="addFiles()">Add Files</button>
<button v-on:click="submitFiles()">Submit</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
files: [],
description: ""
};
},
methods: {
addFiles() {
this.$refs.files.click();
},
submitFiles() {
let formData = new FormData();
let description = this.description;
description = JSON.stringify(description);
for (var i = 0; i < this.files.length; i++) {
let file = this.files[i];
formData.append("files[" + i + "]", file);
formData.append("description[" + i + "]", description);
}
axios
.post("/media", formData, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(function() {
console.log("SUCCESS!!");
})
.catch(function() {
console.log("FAILURE!!");
});
},
handleFilesUpload() {
let uploadedFiles = this.$refs.files.files;
for (var i = 0; i < uploadedFiles.length; i++) {
this.files.push(uploadedFiles[i]);
}
},
removeFile(key) {
this.files.splice(key, 1);
}
}
};
</script>
I am trying to add a description for each file. Does anyone have any ideas please?
Here there is one description model but we need a description model for each file.
So let define them
<template>
<div class="container">
Files
<input
id="files"
ref="files"
type="file"
multiple
#change="handleFilesUpload()"
/>
<div v-for="(item, key) in files" :key="key" class="file-listing">
{{ item.file.name }}
<textarea
v-model="item.description"
name="description"
cols="30"
rows="10"
></textarea>
<span class="remove-file" #click="removeFile(key)">Remove</span>
</div>
<button #click="addFiles()">Add Files</button>
<button #click="submitFiles()">Submit</button>
</div>
</template>
<script>
export default {
data() {
return {
files: [],
description: ''
}
},
methods: {
addFiles() {
this.$refs.files.click()
},
submitFiles() {
let formData = new FormData()
for (var i = 0; i < this.files.length; i++) {
let item = this.files[i]
formData.append('files[' + i + ']', item.file)
formData.append('description[' + i + ']', item.description)
}
axios
.post('/media', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function() {
console.log('SUCCESS!!')
})
.catch(function() {
console.log('FAILURE!!')
})
},
handleFilesUpload() {
let uploadedFiles = this.$refs.files.files
for (var i = 0; i < uploadedFiles.length; i++) {
this.files.push({
file: uploadedFiles[i],
description: ''
})
}
},
removeFile(key) {
this.files.splice(key, 1)
}
}
}
</script>
See working example here
<div class="field relative">
<label>Description</label>
<textarea class="textarea" v-model="description" type="text" maxlength="10000"> </textarea>
<label for="upload-file" class="icn icn-camera cursor-pointer absolute bottom-3 right-4">
<input type="file" id="upload-file" hidden ref="file" #change="getImage($event)" accept="image/**" />
</label>
</div>
use Relative and Absolute position to put the camera icon inside the
textarea
use bottom-3 right-4 to find the proper position
change the default upload file icon to a camera icon