I have tried the many solutions online for trying to get validation to work when loading a partial view, but none of them seemed to work.
I currently have some jQuery code which looks like:
$(".alert").click(function () {
$("#add-comics-container").load("/ManageComics/ComicEditor", function () {
$.validator.unobtrusive.parse("#add-comics-container");
});
$("#add-comics-container").fadeIn();
$(".blackout").css("display", "block");
return false;
});
My /ManageComics/ComicEditor looks like:
public ActionResult ComicEditor() {
return PartialView("_ComicEditorPartial");
}
My Partial more or less looks like:
#model Comics.Models.LocalComicModel
#Html.BeginForm("Index", "ManageComics", FormMethod.Post, new { enctype = "multipart/form-data", id = "addComicForm", value = "1"}){
<div class="add-comics-item">
<div class="add-comics-left">
<span class="add-comics-title bold_text">#Html.LabelFor(u => u.Title)</span>
<div class="add-comics-help">WebComic Title throughout website</div>
#Html.ValidationMessageFor(u => u.Title)
</div>
<div class="add-comics-right">
#Html.TextBoxFor(u => u.Title)
</div>
</div>
}
Related
So I have created a website where you can upload images.
Here's the problem:
I'm using hidden field of input type=file
And I have a designed button which trigger this input.
Now, I have a div that displays those images..
Problem is that I get only the last selected images from the user at my controller.
What happens if the user wants to upload from different directories?
I couldn't find answer after searching, Also I can't show the code right now,
I'm using really simple code tho,
Input of file (multiple)
Button that triggers it
Div that shows the pictures (appended with jquery)
This is a simplified example:
Html:
<button id="inputMask">Upload Image</button>
<div id="ImageHolder">
</div>
<form id="holder" method="post" enctype="multipart/form-data">
<h1>Form</h1>
<input type="submit" />
</form>
JS:
$(document).ready(() => {
let inputs = [];
//Model binding name
let name = "file";
let loadImagesFromInputs = () => {
$("#ImageHolder").empty();
//Lets load those images
if (!FileReader) {
console.log("Cant load files in the navigator");
return;
}
//For each input
inputs.forEach(i => {
//for each file in each input
Array.from(i.files).forEach(f => {
//prepare the file reader
let fr = new FileReader();
//this will run when conversion is finished
fr.onload = function () {
$("#ImageHolder").append($("<img>", {
src: fr.result
}));
}
//convert file to url
fr.readAsDataURL(f);
});
});
}
$("#inputMask").click(() => {
//Create file input
let newInput = $("<input>", {
type: "file",
name: name,
id: name,
multiple: true,
accept: "image/x-png,image/gif,image/jpeg"
}).css({ width: "1", position: "absolute", opacity: "0" });
//update the list of images on change
newInput.change((e) => { loadImagesFromInputs() });
//Add input to list of inputs
inputs.push(newInput[0]);
//Add input to form
$("#holder").append(newInput);
//Click input
newInput.click();
});
$("#holder").submit((e) => {
e.preventDefault();
e.target.submit();
})
});
.Net Core 2 Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace MultipleFileDirectoriesDemo
{
[Route("[controller]")]
public class FileController : Controller
{
// GET: /<controller>/
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(List<IFormFile> file)
{
//Do something with the list of files
return View();
}
}
}
The built in multi-file up-loaders on most browsers are pretty bad.
Consider looking at something like jQuery.Fileuploader
This will have the added benefit of being relatively consistent across devices and browsers.
I am using Angular 2.0.0-beta.0 and TypeScript 1.7.5
When you type something in the search box and something is found and shown on the screen, then you delete the search input box and you want to show an empty list. It work using this piece of code:
this.searchTermStream.next("makesureyoudontfindanything");
Does anyone has a better cleaner solution without doing a http request?
#Component({
selector: 'contact-search',
template: `
<div class="container">
<div class="form-group">
<label for="inputUser">Search</label>
<input #inputUser (keyup)="search(inputUser.value)">
</div>
<ul>
<li *ngFor="#contact of contactList | async">{{contact.name}}</li>
</ul>
</div>
`
})
export class ContactSearch {
private searchTermStream = new Subject<string>();
private contactList: Observable<Contact[]> = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((value: string) => this.contactService.searchContacts(value))
constructor(private contactService: ContactService) {}
search(value: string) {
if (value) {
this.searchTermStream.next(value);
}
else {
this.searchTermStream.next("makesureyoudontfindanything");
}
}
}
You can check if value is empty before calling service:
private contactList: Observable<Contact[]> = this.searchTermStream
.debounceTime(300)
.distinctUntilChanged()
.switchMap((value: string) =>
0 < value.length ? this.contactService.searchContacts(value) : Observable.of([]))
search(value: string) {
this.searchTermStream.next(value);
}
I am having trouble passing data between controllers using a service. What i want to happen is when send data is clicked the data inputted into the text field should be populated in the Results controller. However nothing shows
Home.html:
<html>
<body>
<ion-header-bar class="bar-dark">
<h1 class="title"></h1>
</ion-header-bar>
<ion-view view-title="Home">
<ion-content ng-controller="StockUpdateCtrl">
<div class="list">
<ion-refresher pulling-text="Pull to Refresh" on-refresh="doRefresh()"></ion-refresher>
<div>{{text}}</div>
<input type='text' ng-model='text' />
<button type='button' ng-click='send()'>Send Data</button>
<div ng-controller='ResultsController'>
<div>
<h4>Ctrl2</h4>
<div>{{text}}</div>
</div>
</div>
</ion-content>
</ion-view>
</body>
</html>
HomeController.js:
var app = angular.module('starter', ['ionic'])
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
});
})
/*
* Data Service
* Service used to pass data between controllers
*/
app.factory('dataShare', function(){
var service = {};
service.data = false;
service.sendData = function(data){
this.data = data;
$rootScope.$broadcast('data_shared');
};
service.getData = function(){
return this.data;
};
return service;
});
/*
* Stock Update Controller
* Gets user input and then performs calculations to prepare to be displayed
*
*/
app.controller("StockUpdateCtrl", function ($scope, $http, dataShare) {
$scope.text = 'Hey';
$scope.send = function(){
dataShare.sendData($scope.text);
};
});
ResultsController.js:
* Resultse Controller
* Displays the results
*
*/
app.controller("ResultsController",function ($scope, dataShare) {
$scope.text = '';
$scope.$on('data_shared',function(){
var text = dataShare.getData();
$scope.text = text;
});
});
Haha figured it out. Yes it turned out it was the way i was calling the results page... I had to remove form tag
<form action="index.html#/results" ng-controller="StockUpdateCtrl">
and change my button to call the results page as such
<button type="submit" ui-sref="results" ng-click="calculate()" class="button button-block button-balanced">
I added the Bootstrap dual listbox plugin on my project and it's working fine, but how can I pass the contents of the selected listbox to my controller? It's already inside a form but if I try to get it through FormCollection it returns as null.
View:
<div class="form-group col-md-7" style="margin-left: -15px;">
<select style="display: none;" multiple="multiple" size="10" name="dualListbox" id="dualListbox" class="demo2">
#if (ViewData["Customers"] != null)
{
foreach (var item in ViewData["Customers"] as List<Testbox.Models.Customer>)
{
<option value="customer">#item.NAME #item.LName - #item.PHONE11</option>
}
}
</select>
</div>
Well you can do it as below:
I'll assume that your form id is demoform and below is how the post action method will look like:
[HttpPost]
public ActionResult GetForm()
{
string values = Request.Form["dualListbox"];
//Form[key] will be 'name' property of your select box
//You will get values as comma ',' separated values like option 1,
//option 2, option 4 etc., and I hope you know how you can get each
//options by splitting the comma separated values.
......
......
}
Here is an example to your question. Maybe this will help people in the future.
The trick is in the JS.
Let's say you want to use Bootstrap Dual Listbox in conjuction with ASP.NET MVC 4 and Kendo framework.
We will use the Razor syntax and C#.
First, we write in the view the placeholder for the code. We will be linking a kendo control and the Bootstrap Dual Listbox
<script>
var urlGetCascadeMultiSelectBrandTypeByBrand = "#(Url.Action("GetCascadeMultiSelectBrandTypeByBrand", "DropDownList"))";
</script>
<div class="col-md-12 col-sm-12 col-xs-12 padding-0 ">
<div class="col-md-6 col-sm-6 col-xs-12">
#Html.LabelFor(m => m.BrandId)<br />
#(Html.Kendo().DropDownListFor(m => m.BrandId)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetCascadeDdlBrandBySegment", "DropDownList")
.Data("filterSegments");
})
.ServerFiltering(true);
})
.DataTextField("BrandName")
.DataValueField("BrandId")
.Filter(FilterType.Contains)
.CascadeFrom("SegmentId")
.OptionLabel("Select brand")
.Events(evt => evt.Change("onBrandIdDdlChange"))
.HtmlAttributes(new { #style = "width: 100%;" }))
#Html.ValidationMessageFor(m => m.BrandId)
</div>
<div class="col-md-6 col-sm-6 col-xs-12">
</div>
</div>
<div class="clear height10"></div>
<div class="col-md-12 col-sm-12 col-xs-12 padding-0 ">
<div class="col-md-12 col-sm-12 col-xs-12">
#Html.LabelFor(m => m.BrandTypeIdList)<br />
#if (Model.IsEdit)
{
#Html.ListBoxFor(m => m.BrandTypeIdList, Html.GetBrandTypeByBrandIdSelectListItemsList(Model.BrandId))
}
else
{
#Html.ListBoxFor(m => m.BrandTypeIdList, new List<SelectListItem>())
}
#Html.ValidationMessageFor(m => m.BrandTypeIdList)
</div>
</div>
Then, we create the C# helper code to go with it.
public static IEnumerable<SelectListItem> GetBrandTypeByBrandIdSelectListItemsList(this HtmlHelper htmlHelper, int brandId)
{
using (var dbContext = new Entities())
{
return dbContext.BrandType.Where(x => x.Active == true && x.BrandId == brandId).Select(BrandTypeToDdlSelector).ToList();
}
}
public static Func<BrandType, SelectListItem> BrandTypeToDdlSelector
{
get
{
return (x => new SelectListItem()
{
Value = x.BrandTypeId.ToString(),
Text = x.Name
});
}
}
public JsonResult GetCascadeMultiSelectBrandTypeByBrand(int? brandId)
{
var brandTypesList = DbContext.BrandType.Where(p => p.Active == true);
if (brandId != null)
{
brandTypesList = brandTypesList.Where(p => p.BrandId == brandId);
}
return Json(brandTypesList.Select(x => new { BrandTypeId = x.BrandTypeId, BrandTypeName = x.Name }), JsonRequestBehavior.AllowGet);
}
Then we create the JS code to manipulate the HTML at runtime and bind the selected values to the MVC model.
var brandTypeIdDualListbox = new Object();
$(document).ready(function ()
{
//we create the dual list control
brandTypeIdDualListbox = $('select[name="BrandTypeIdList"]').bootstrapDualListbox({
nonSelectedListLabel: 'Non-selected',
selectedListLabel: 'Selected',
preserveSelectionOnMove: 'moved',
moveOnSelect: false,
});
//we setup the change event for the control
$('select[name="BrandTypeIdList').on('change', function (args)
{
//we traverse every option
$("#BrandTypeIdList option").each(function (index,element)
{
//we check if the element has the `data-sortindex` attribute
if (!!$(element).attr('data-sortindex'))
$(element).attr('selected', 'selected');
else
$(element).removeAttr('selected');
});
})
});
function filterBrands()
{
var brandId = $("#BrandId").val();
if (brandId == "")
brandId = "-1";
return {
BrandId: brandId
};
}
function populateBrandTypeIdDualListbox()
{
$.getJSON(urlGetCascadeMultiSelectBrandTypeByBrand, filterBrands(), function (data)
{
var items;
$.each(data, function (i, item)
{
brandTypeIdDualListbox.append("<option value=" + item.BrandTypeId/*Value*/ + ">" + item.BrandTypeName/*Key or Text*/ + "</option>");
});
brandTypeIdDualListbox.trigger('bootstrapDualListbox.refresh', true); // we refresh the control
});
}
function onBrandIdDdlChange(evt)
{
var brandIdDropDownList = $("#BrandId").data("kendoDropDownList");
$('#BrandTypeIdList').empty();
brandTypeIdDualListbox.trigger('bootstrapDualListbox.refresh', true);
if ($("#BrandId").val() == "" || $("#BrandId").val() == "-1")
{
//if no value is selected we disable the control
$(".bootstrap-duallistbox-container").find("*").prop("disabled", true);
}
else
{
populateBrandTypeIdDualListbox();
$(".bootstrap-duallistbox-container").find("*").prop("disabled", false); // we enable the control
}
}
I've been trying to get MVC Jquery unobtrusive error handling working with twitter bootstrap for some time now. Its got to the point were i'm either going to edit jquery.validate or do some hack and slash on document.ready.
In order to get unobtrusive error handling to work with Bootstrap and MVC I need to make it so the 'error' class it appended to the 'control-group' class. As well as that, the 'error' class is appended to the input.
I was wondering if anyone in the community has already found a solution.
For example
Typical bootstrap markup would be like so...
<div class="control-group">
<label for="Username">Username</label>
<div class="controls">
<input data-val="true" data-val-required="Username is required" id="Username" name="Username" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Username" data-valmsg-replace="true"></span>
</div>
</div>
What should happen, on blur when jquery.validate unobtrusive fires... it would change to the following
<div class="control-group error">
<label for="Username">Username</label>
<div class="controls">
<input data-val="true" data-val-required="Username is required" id="Username" name="Username" type="text" value="" />
<span class="field-validation-valid help-inline" data-valmsg-for="Username" data-valmsg-replace="true"></span>
</div>
</div>
To get this to work on postback/submit you can do the following...
//twitter bootstrap on post
$(function () {
$('span.field-validation-valid, span.field-validation-error').each(function () {
$(this).addClass('help-inline');
});
$('form').submit(function () {
if ($(this).valid()) {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length == 0) {
$(this).removeClass('error');
}
});
}
else {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('error');
}
});
}
});
$('form').each(function () {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('error');
}
});
});
});
However, on blur it won't work as you'd expect. I don't want to edit the bootstrap CSS, or Jquery.validate files as they will likely roll out an update at some-point.
Would I create a delegate, or a bind to the jquery functions and work from there. This is deep JS code which I'm not familiar with but could with time firefight my way through it.
Does any one know where I'd start with this problem, or know where it is implemented/been discussed?
var page = function () {
//Update that validator
$.validator.setDefaults({
highlight: function (element) {
$(element).closest(".control-group").addClass("error");
},
unhighlight: function (element) {
$(element).closest(".control-group").removeClass("error");
}
});
} ();
Finally, this fixed it for me. I hope this helps other people too...
My final JS ended like so.
$(function () {
$('span.field-validation-valid, span.field-validation-error').each(function () {
$(this).addClass('help-inline');
});
$('form').submit(function () {
if ($(this).valid()) {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length == 0) {
$(this).removeClass('error');
}
});
}
else {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('error');
}
});
}
});
$('form').each(function () {
$(this).find('div.control-group').each(function () {
if ($(this).find('span.field-validation-error').length > 0) {
$(this).addClass('error');
}
});
});
});
var page = function () {
//Update that validator
$.validator.setDefaults({
highlight: function (element) {
$(element).closest(".control-group").addClass("error");
},
unhighlight: function (element) {
$(element).closest(".control-group").removeClass("error");
}
});
} ();
Here's a nice solution...
Add this to your _Layout.cshtml file outside jQuery(document).ready():
<script type="text/javascript">
jQuery.validator.setDefaults({
highlight: function (element, errorClass, validClass) {
if (element.type === 'radio') {
this.findByName(element.name).addClass(errorClass).removeClass(validClass);
} else {
$(element).addClass(errorClass).removeClass(validClass);
$(element).closest('.control-group').removeClass('success').addClass('error');
}
},
unhighlight: function (element, errorClass, validClass) {
if (element.type === 'radio') {
this.findByName(element.name).removeClass(errorClass).addClass(validClass);
} else {
$(element).removeClass(errorClass).addClass(validClass);
$(element).closest('.control-group').removeClass('error').addClass('success');
}
}
});
</script>
Add this inside $(document).ready():
$("span.field-validation-valid, span.field-validation-error").addClass('help-inline');
$("div.control-group").has("span.field-validation-error").addClass('error');
$("div.validation-summary-errors").has("li:visible").addClass("alert alert-block alert-error");
You're good to go.
Code pieces taken from:
Twitter Bootstrap validation styles with ASP.NET MVC
Integrating Bootstrap Error styling with MVC’s Unobtrusive Error Validation
#daveb's answer
In addition to the answer provided by #leniel-macaferi I use the following as my $(document).ready() function:
$(function () {
$("span.field-validation-valid, span.field-validation-error").addClass('help-inline');
$("div.control-group").has("span.field-validation-error").addClass('error');
$("div.validation-summary-errors").has("li:visible").addClass("alert alert-block alert-error");
});
This also sets the "error" class on the control group if server side validation has failed on a form post and formats any validation summary nicely as a bootstrap error alert.
I know this is an oldy, but I thought I'd share my answer to update for Bootstrap 3. I scratched my head for quite sometime, before building on top of the solution given by Leniel Macaferi.
On top of changing the clases to reflect Bootstrap 3, I thought it would be a nice touch to present the user with a glyphicon to represent the state of the field.
(function ($) {
var defaultOptions = {
errorClass: 'has-error has-feedback',
validClass: 'has-success has-feedback',
highlight: function (element, errorClass, validClass) {
var _formGroup = $(element).closest(".form-group");
_formGroup
.addClass('has-error')
.removeClass('has-success');
if (!_formGroup.hasClass("has-feedback")) {
_formGroup.addClass("has-feedback");
}
var _feedbackIcon = $(element).closest(".form-group").find(".glyphicon");
if (_feedbackIcon.length) {
$(_feedbackIcon)
.removeClass("glyphicon-ok")
.removeClass("glyphicon-remove")
.addClass("glyphicon-remove");
}
else {
$("<span class='glyphicon glyphicon-remove form-control-feedback' aria-hidden='true'></span>")
.insertAfter(element);
}
},
unhighlight: function (element, errorClass, validClass) {
var _formGroup = $(element).closest(".form-group");
_formGroup
.removeClass('has-error')
.addClass('has-success');
if (!_formGroup.hasClass("has-feedback")) {
_formGroup.addClass("has-feedback");
}
var _feedbackIcon = $(element).closest(".form-group").find(".glyphicon");
if (_feedbackIcon.length) {
$(_feedbackIcon)
.removeClass("glyphicon-ok")
.removeClass("glyphicon-remove")
.addClass("glyphicon-ok");
}
else {
$("<span class='glyphicon glyphicon-ok form-control-feedback' aria-hidden='true'></span>")
.insertAfter(element);
}
}
};
$.validator.setDefaults(defaultOptions);
$.validator.unobtrusive.options = {
errorClass: defaultOptions.errorClass,
validClass: defaultOptions.validClass,
};
})(jQuery);
Try use this plugin I've made https://github.com/sandrocaseiro/jquery.validate.unobtrusive.bootstrap
What I did differently from the others answers was to override the errorPlacement and success methods from validate.unobtrusive with my own implementations, but without removing the original implementation so nothing will break.
My implementation look like this:
erroPlacement:
function onError(formElement, error, inputElement) {
var container = $(formElement).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
//calling original validate.unobtrusive method
errorPlacementBase(error, inputElement);
if (replace) {
var group = inputElement.parent();
if (group.hasClass('form-group')) {
group.addClass('has-error').removeClass('has-success');
}
group = group.parent();
if (group.hasClass('form-group')) {
group.addClass('has-error').removeClass('has-success');
}
}
}
success:
function onSuccess(error) {
var container = error.data("unobtrusiveContainer");
//calling original validate.unobtrusive method
successBase(error);
if (container) {
var group = container.parent();
if (group.hasClass('form-group')) {
group.addClass('has-success').removeClass('has-error');
}
group = group.parent();
if (group.hasClass('form-group')) {
group.addClass('has-success').removeClass('has-error');
}
}
}
Out of the box I wanted on blur to raise my error validation. I found this wasn't the case with Jquery Unobtrusive. It seemed to work if you had a select input but not on a text type input. To get around this for me, perhaps its clumsy but I used the following.
$(function () {
$("input[type='text']").blur(function () {
$('form').validate().element(this);
});
});
You can change it is just enabled on certain inputs that have a specific css class.
$(function () {
$(".EnableOnblurUnobtrusiveValidation").blur(function () {
$('form').validate().element(this);
});
});
EnableOnblurUnobtrusiveValidation... is a bit of a long name but you get the jist.
Use TwitterBootstrapMvc.
It takes care of unobtrusive validation attributes automatically and all you have to write to get a full control group with label, input and validation is:
#Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Field)
Good luck!