All,
I need to add validation rules to dynamic form input text elements added by the user.
I am accomplishing this by cloning a chunk of HTML, providing unique ids and adding to the DOM
I researched the syntax for this, which I believe is correct yet I am getting the following JS error when I try to access the .rules method:
TypeError: $(...).rules is not a function
Caused by this:
$("input[type=text].validateRequired").each(function () {
$(this).rules("add", { required: true, messages: { required: "Data is missing" }
});
});
When I examine $(this) in FireBug, I do not see a .rules method yet it exists in the validation scripts and all of the documentation shows that the method should be available globally. Not sure how to get it in scope.
Here are the code pieces in the View related to this problem:
JS Includes
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
JS Method that creates the dynamic form elements
<script type="text/javascript">
$(document).ready(function() {
var uniqueId = 1;
var ctr = 1;
$(function() {
$('.js-add-cosponsor-hyperlink').click(function() {
var copy = $("#cosponsorsTemplate").clone(true).appendTo("#addCosponsorSection").hide().fadeIn('slow');
var cosponsorDivId = 'cosponsors_' + uniqueId;
var copyText = copy.html();
copyText = copyText.replace(/Guitar1/g, 'Guitar' + ctr);
copyText = copyText.replace('Guitar_1', 'Guitar_' + ctr);
copy.html(copyText);
$('#cosponsorsTemplate').attr('id', cosponsorDivId);
var deleteLink = copy.find("a.icon.delete");
deleteLink.on('click', function() {
copy.fadeOut(300, function() { $(this).remove(); }); //fade out the removal
});
$.validator.unobtrusive.parse(form);
$("input[type=text].validateRequired").each(function () {
var t = $(this);
$(this).rules("add", { required: true, messages: { required: "Data is missing" } });
});
uniqueId++;
ctr++;
});
});
});
</script>
*The Form*
#using (Html.BeginForm())
{
[...]
<!-- Template used to do the Clone: These need dynamic validation -->
<div style="display:none">
<div id="cosponsorsTemplate">
<div class="formColumn1"><label>Guitar</label></div>
<div class="formColumn2">#Html.TextBoxFor(model => model.Guitar1.Make, new { Placeholder = "Make", Class = "validateRequired" })
<div class="messageBottom">
#Html.ValidationMessageFor(model => model.Guitar1.Make)
</div>
</div>
<div class="formColumn3">#Html.TextBoxFor(model => model.Guitar1.Model, new { Placeholder = "Model" , Class = "validateRequired"})
<div class="messageBottom">
#Html.ValidationMessageFor(model => model.Guitar1.Model)
</div>
</div>
<div class="formColumn4">#Html.TextBoxFor(model => model.Guitar1.ProductionYear, new { Placeholder = "Production Year", Class = "validateRequired" })
<div class="messageBottom">
#Html.ValidationMessageFor(model => model.Guitar1.ProductionYear)
</div><a class="icon delete">Delete</a>
</div>
</div>
</div>
<!-- End Add Co-Sponsor Row Template -->
}
You are cloning a chunk of HTML so every time you do a clone you need to parse the whole form
by using $.validator.unobtrusive.parse
Related
I am using MVC and in View i want to bind a textbox to google API to get auto complete address, How to do this in MVC??
Note: I dont want to display google maps. just textbox show suggestions .. I Did something like this
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAacPaT9YiOu-8leoacd1RDbRfx7an1u74&libraries=places&callback=initMap"
async defer></script>
<script>
google.maps.event.addDomListener(AddNewJob, 'load', function () {
var options = {
types: ['(cities)'],
componentRestrictions: { country: "in" }
};
});
autocomplete = new google.maps.places.Autocomplete(document.getElementById('FromAddress'));
autocomplete.addListener();
</script>
}
And in textBox
<div class="form-group">
#Html.LabelFor(model => model.FromAddress, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" id="FromAddress" />
#Html.ValidationMessageFor(model => model.FromAddress, "", new { #class = "text-danger" })
</div>
</div>
var input = document.getElementById('your input tag id');
var autocomplete = new google.maps.places.Autocomplete(input);
Use javascript to do it. Follow api documentation
Check it out on jsfiddle
To do this, you'll need a Maps API Key which you can obtain here : https://developers.google.com/maps/documentation/embed/get-api-key.
Replace YOUR_API_KEY in the scripts url with the api key you obtain from the link above.
Change the id to match the id of the input element you want to attach this to. In the example below, the input element's id is "FromAddress".
And you might want to change options or remove it entirely depending on your needs as the current setting limits the auto-completion to cities in India.
#section Scripts {
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap" async="" defer=""></script>
<script>
function initMap() {
google.maps.event.addDomListener(window, 'load', function () {
var options = {
types: ['(cities)'],
componentRestrictions: { country: "in" }
};
var input = document.getElementById('FromAddress');
var places = new google.maps.places.Autocomplete(input, options);
});
}
</script>
}
I'm still new to asp.net mvc, i want to delete list of partial view, the delete is working but i must reload the entire page to show the new list
What I want is the partial view show the new list after delete without load the entire page, so only the partial view is updated
Here is my code:
My view content some of partial view :
#model cc.Models.User
#{
Layout = "~/Views/Shared/_MemberLayout.cshtml";
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcValidation.debug.js")" type="text/javascript"></script>
<body class="container body-content">
<div id="partialView1">
#Html.Action(...)
</div>
<div id="partialView2">
#Html.Action(...)
</div>
<div id="partialView4">
#Html.Action(...)
</div>
<div id="partialView3" class="col-md-8 col-sm-1">
#Html.Action("UserHistory", "User")
</div>
</body>
Here is my partial view for UserHistory I tried to use ajax but it's not work. I already tried to use
$(this).closest('.historyRow').remove();
and
$("a.deleteHistory").live("click", function () {
$(this).parents("div.historyRow:first").remove();
return false;
});
Here is my code :
#model cc.Models.UserHistory
#{
Layout = null;
}
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="#Url.Content("~/Scripts/MicrosoftAjax.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MicrosoftMvcValidation.debug.js")" type="text/javascript"></script>
<div id="formHistory">
<div id="historyDetail">
<div id="editDataHistoryUser">
#foreach (var item in Model.History)
{
#Html.Partial("UserHistoryDetail", item)
}
</div>
#Html.ActionLink("Add Form", "AddUserHistory", null, new { id = "btnFormHistory" })
</div>
</div>
<script type="text/javascript">
$("#btnFormHistory").click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) { $("#editDataHistoryUser").append(html); }
});
return false;
});
$('#formHistory').on('click', '.deleteHistory', function () {
var id = $(this).data('id');
if (id == 0) {
$(this).closest('.historyRow').remove();
//$("a.deleteHistory").live("click", function () {
// $(this).parents("div.historyRow:first").remove();
// return false;
//});
} else {
var url = '#Url.Action("DeleteUserHistory", "User")';
$.post(url, { ID: id }, function (response) {
if (response) {
$(this).closest('.historyRow').remove();
//$("a.deleteHistory").live("click", function () {
// $(this).parents("div.historyRow:first").remove();
// return false;
//});
}
}).fail(function (response) {
});
}
});
</script>
Here is my UserHistoryDetail Code :
#model cc.Models.IUserHistory
#{
Layout = null;
}
<div id="formUserHistoryDetail">
#using (Ajax.BeginForm("UserHistoryDetail", "User", new AjaxOptions { HttpMethod = "POST" }))
{
<div id="historyRow">
<div>#Html.LabelFor(model => model.IDHistory, new { style = "display:none;" })</div>
...
delete
</div>
}
</div>
And here is my JsonResult when button delete clicked :
[HttpPost]
public JsonResult DeleteUserHistory(string ID)
{
db.delUserHistory(ID);
return Json(true);
}
I still cannot find the solution for this , or maybe i used ajax in wrong way, any suggestion?
Let's assume that the DeleteUserHistory post url is '/[Controller]/': '/UserHistory'
$('.deleteHistory').click(function(){
var url = '/UserHistory';
$.ajax({
type: "POST",
url: url,
data: data,
success: onSuccessCallback
});
});
What you should really do is use WebApi to manage data and use the views to display.
As for the delete, use method type 'delete' instead of 'post'. Post should be used for "adds".
SO i have this jquery template and i need to call a jquery or javascript function on the click of this anchor tag. Ive tried it a few different ways.
<a href="yourfunction()"
Ive tried
$('#number').click(function(e){
So if anyone could help it would be highly appreciated. The anchor tag in question is the phone number one with the id of number.
#model OpenRoad.Web.Areas.Marketing.Models.MobyNumberSelectionModel
#{
ViewBag.Title = "Moby Number Selection";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section scripts {
<script type ="text/javascript">
$('#number').click(function (e) {
alert('test');
});
});
mixpanel.track("View Marketing | Moby | Number Selection");
//$(document).on("click", "#number", function (e) {
// event.preventDefault();
// alert('test'); });
//$('#number').click(function (e) {
// Alert('test');
//});
</script>
}
<label class="lgform" style="text-align: left; padding: 10px 0;">Select state and area code:</label>
#Html.DropDownListFor(m => m.State, OpenRoad.Web.Helpers.DropDownLists.GetOptionValues("States", Model.State),
new { #class = "ddtrigger", data_url = "/Marketing/Moby/GetAreaCodes", data_template = "areaCodeTemplate", data_target = "AreaCode" })
#Html.DropDownListFor(m => m.AreaCode, (IEnumerable<SelectListItem>)ViewData["AreaCodes"],
new { #class = "ddtrigger", data_url = "/Marketing/Moby/GetPhoneNumbers",
data_template = "phoneNumberTemplate",
data_target = "phoneNumbers",
data_listtarget="true" })
#Html.HiddenFor(m => m.MobyNumber)
<script id="areaCodeTemplate" type="text/x-jquery-template">
<option value="${AreaCode}">${AreaCode}</option>
</script>
<br />
<script id="phoneNumberTemplate" type="text/x-jquery-template">
<div class="numberselectbox">
<strong>${FormattedPhoneNumber}</strong> Select<br/>
</div>
</script>
<div id="phoneNumbers">
</div>
Since you are using a template to generate the elements, these elements will be dynamic so you need to use delegated event model.
Also since it is a template, do not use static id for the elements since the elements can be duplicated - use class attribute instead
<script id="phoneNumberTemplate" type="text/x-jquery-template">
<div class="numberselectbox">
<strong>${FormattedPhoneNumber}</strong> Select<br/>
</div>
$(document).on('click', '.number', function(){
//do something
})
You could try jQuery's on() method or click() shorthand:
$(document).ready( function() {
$('#number').on('click', function(e){
// your method implementation here
e.preventDefault();
});
// OR //
$('#number').click(function(e){
// your method implementation here
e.preventDefault();
});
});
I have this script, what it intends to do is: in a view with a list of contacts, each one with a edit link whenever you click on one of these links it displays an edit form in a partial view (there's only one div in the parent view for holding it) just below the clicked contact, for that it does a get ajax call to the server and gets the information for that contact. After submitting, via ajax as well, it refreshes the list.
Everything seems to work fine, but if I edit a contact, after the list being refreshed I try to open again the form on the same contact and the information is the same as it was before being edited. Although debugging I see the list for the server is correct (and so is the display in the list, it's only wrong in the form)
Thing is that in chrome developer tool I can see the form with some "default values" set to the previous stuff. I didn't know about them till now and I don't know how to get rid of them, because to my understanding I'm making a get call to the server, anyway I have tried this
document.getElementById("editForm").reset();
with no luck.
Thanks
The script
(function ($) {
var editContainer = $(document.getElementById('editContainer'));
$('#editContainer').on('submit', '#editForm', ajaxEditCall);
$('a.edit').on("click", displayEditForm);
function displayEditForm(e) {
var clickedElement = $(this).parent(),
url = editContainer.data('amp-edit-url');
$.get(url, {
id: parseInt(this.id, 10)
}, function (result) {
editContainer.html(result);
$.validator.unobtrusive.parse(editContainer);
// Display edit form just below the "item" clicked
if (editContainer.is(":visible")) {
editContainer.slideToggle(300, function () {
editContainer.appendTo(clickedElement);
editContainer.slideToggle(300);
});
} else {
editContainer.appendTo(clickedElement);
editContainer.slideToggle(300);
}
}, "html");
e.preventDefault();
}
function ajaxEditCall(e) {
e.preventDefault();
//if ($('#editForm').valid()) {
var list = $(document.getElementById('list'));
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.passedValidation == true) {
$.get(result.action, function (partial) {
document.getElementById("editForm").reset();
list.html(partial);
$('a.edit').on("click", displayEditForm);
$('#editForm').slideUp(300);
setTimeout(function () {
list.effect("highlight", {}, 3000);
}, 1000);
});
} else {
$(document).scrollTop(0);
editContainer.html(result);
$.validator.unobtrusive.parse('#editForm');
}
}
});
//} return false;
}
}(jQuery));
And the view in case is relevant
#model ContactListViewModel
#{
ViewBag.Title = " My Contacts";
}
<div id="myContacts">
<h2>My Contacts</h2>
<div id="editContainer" data-amp-edit-url="#Url.Action("Edit", "Contacts")" class="initiallyHidden"></div>
<div id="list">
#{ Html.RenderPartial("_ContactList", Model); }
</div>
<div id="dialog" data-amp-del-url="#Url.Action("Delete", "Contacts")" title="Confirmation Required">
<p>Are you sure you want to delete this Contact?</p>
</div>
</div>
#section Foot
{
<script src="~/Scripts/AMPContacts.js"></script>
<script src="~/Scripts/conditional-validation.js"></script>
<script src="~/Scripts/Placeholders.min.js"></script>
}
Well that's obviously the parent view, the partial one is just a bunch of fields, I remove most of them to avoid increase the already long post
#model AddContactViewModel
#using (Html.BeginForm("Edit", "Contacts", FormMethod.Post, new { #id = "editForm", #class = "addTab" }))
{
#Html.ValidationSummary(true, "Please correct the errors and try again.")
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.OwnedItemId)
#Html.HiddenFor(m => m.AddressId)
<div id="editContactDetails">
<div>
#Html.DisplayFor(m => m.PlanName)
</div>
<div>
#Html.DropDownListFor(m => m.Title, Model.TitleList, "Title")
</div>
<div>
#Html.EditorFor(m => m.FirstName, new { #id="editFirstName", data_placeholders_focus = "false", placeholder = ViewData.ModelMetadata.Watermark })
#Html.ValidationMessageFor(m => m.FirstName)
</div>
// And so on....
<div class="addDEC">
<input class="addDECButton" type="submit" value="Save" />
</div>
}
I ran into this problem with a site I was working on. You'll need to disable your ajax caching:
//Disbable cache for all jQuery AJAX requests
$.ajaxSetup({ cache: false });
That will do it for all ajax calls, so you may only want to do that on certain pages, depending on your usage.
I am using CKeditor in MVC 3 app.
Right now i am in need of saving text with HTML tags to DB, problem is that Ckeditors GetData() method returns raw format of data (http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.editor.html#getData)
I need a way to make that raw format to normal string with Html tags
View :
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>TextEditionViewModel</legend>
#Html.DropDownListFor(model=>model.Id, Model.Texts)
<div class="editor-label">
#Html.LabelFor(model => model.Text)
</div>
<div class="editor-field">
#Html.TextAreaFor((model => model.Text), new { #Id = "editor1" })
#Html.ValidationMessageFor(model => model.Text)
</div>
<script type="text/javascript">
CKEDITOR.replace('editor1');
</script>
<script type="text/javascript">
var editor_data = CKEDITOR.instances['editor1'].getData();
var url = '#Url.Action("EditText1", "Admin")';
var data = { CommentText: editor_data };
function Save() {
alert(editor_data);
$.post(url, { CommentText: editor_data }, function (result) {
});
};
$('#Id').change(function () {
var selectedText = $(this).val();
if (selectedText != null && selectedText != '') {
$.getJSON('#Url.Action("Text","Admin")', { Id: selectedText }, function (text) {
CKEDITOR.instances['editor1'].setData(text);
});
}
});
</script>
</fieldset>
<p>
<input type="button" value="Save" onclick="Save()"/>
</p>
}
If editor_data is set to Normal "Text" string everything works!
Controller
public ActionResult EditText1(String CommentText)
{
return null;
}
You could decorate your controller action with the [ValidateInput] attribute to allow POSTing HTML tags which is not authorized by ASP.NET by default:
[HttpPost]
[ValidateInput(false)]
public ActionResult EditText1(string commentText)
{
return null;
}
UPDATE:
The problem is related to the fact that the editor_data variable is not accessible in the Save method.
You could do this:
<script type="text/javascript">
function Save() {
var editor_data = CKEDITOR.instances['editor1'].getData();
var url = '#Url.Action("EditText1", "Admin")';
var data = { CommentText: editor_data };
$.post(url, data, function (result) {
});
}
...
</script>