jQuery and #Html.TextBoxfor() - asp.net

I currently have the following code:
[HttpPost]
public ActionResult Index(IList<LocalPageModel> postPages,
IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
foreach (HttpPostedFileBase file in files)
{
if ((file != null) && (file.ContentLength > 0))
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/"),
fileName);
file.SaveAs(path);
}
}
}
else
{
ManagePagesModel mod = new ManagePagesModel
{
PostPages = postPages
};
return View("Index", mod);
}
return RedirectToAction("Index");
}
In my view, I have a JavaScript button which will add a div so that the user can post another page such as:
$("#add-page").click(function () {
$("#page").append('<div id="page"> #Html.TextBoxFor(u => u.PostPages[0].Title) </div>');
});
How do I make it so that when the user clicks on the JavaScript button, the new text will be appended to the page and u.PostPages[x] will be incremented?

If you want to do it all on the client (no AJAX), maybe don't use the MVC helpers at all, and do it manually instead - you know the HTML that will be rendered, so just do that:
var i = 0;
$("#add-page").click(function () {
$("#page").append('<input type="text" name="PostPages[' + (i++) + '].Title">');
});
Maybe clean the code up a bit so the quotes don't get too confusing, but you get the idea...

You didn't past your view, but I assume you have the following at the top:
#model = ManagePagesModel
If that's the case, you can then use the following #foreach to loop through the page models:
$("#add-page).click(function() {
#foreach(var pageModel in Model.PostPages){
$("#page").append('<div id="page"> #Html.TextBoxFor(u => pageModel.Title) </div>');
});

To increment u.PostPages[x] you may use following code:
<script>
var i = 0;
$("#add-page").click(function () {
i++
$("#page").append('<div id="page"> #Html.TextBoxFor(u => u.PostPages['+i+'].Title') </div>');
});
</script>
Here is small working example: jsfiddle

Related

View not returned properly in ASP.NET MVC Core 6

On click of the button, a javascript function is called that captures the snapshot from the camera and sends it to process. On backed, we get the image and do some process and get the data in an object called "doc". Upto here the system works fine, but the data that I got in "doc" object doesn't seem to be printed on the page.
Here's the button
<input type="button" value="Capture Snapshot" onClick="CaptureSnapshot()">
And here's the javascript
<script language="JavaScript">
function CaptureSnapshot() {
Webcam.snap(function (data) {
// display results in page
document.getElementById('results').innerHTML = '<img src="' + data + '"/>';
// Send image data to the controller to store locally or in database
Webcam.upload(data,
'/Home/UploadFile',
function (code, text) {
Webcam.reset();
//alert('Snapshot/Image captured successfully...');
});
});
}
</script>
And this is the C# method written in the controller
public async Task<IActionResult> UploadFile()
{
var files = HttpContext.Request.Form.Files;
if (files != null && files.Count > 0)
{
foreach (var uploadedFile in files)
{
if (uploadedFile.Length > 0)
{
var fileName = uploadedFile.FileName;
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", fileName);
HttpContext.Session.SetString("UploadedFile", fileName);
byte[] imageBytes = ConvertToBytes(uploadedFile);
Document doc = ProcessDocumentImage(imageBytes);
ViewData["Document"] = doc;
}
}
}
else
return Content("file not selected");
return View("Index", "Home");
}
If I put a breakpoint on "doc", I get the data but it doesn't go on the page. What I found is that the page is not submitted at all, maybe this is the reason.
Any ideas to solve this?

I cant using Html.RenderAction in .cshtml

FRONTEND
#{
<div>
#Html.RenderAction("UrunOzellikTipWidget", "Admin");
#Html.RenderAction("UrunOzellikDegerWidget", "Admin");
</div>
}
BACKEND
public ActionResult UrunOzellikEkle()
{
return View(Context.Baglanti.Urun.ToList());
}
public PartialViewResult UrunOzellikTipWidged(int? katID)
{
if (katID != null)
{
var data = Context.Baglanti.OzellikTip
.Where(x => x.KategoriID == katID)
.ToList();
return PartialView(data);
}
else
{
var data = Context.Baglanti.OzellikTip.ToList();
return PartialView(data);
}
}
public PartialViewResult UrunOzellikDegerWidget(int? tipID)
{
if (tipID != null)
{
var data = Context.Baglanti.OzellikDeger
.Where(x => x.OzellikTipID == tipID)
.ToList();
return PartialView(data);
}
else
{
var data = Context.Baglanti.OzellikDeger
.ToList();
return PartialView(data);
}
}
**ERROR CODE:Severity Code Description Project File Line Suppression State Error CS0029 Cannot implicitly convert type 'void' to 'object'
**
#Html.RenderAction renders the result and, instead of returns it as string, writes it directly to the response and returns Void. So you will have to use it inside a C# block, denoted as #{ }, and end it with a semicolon at the end, just like how you invoke/call a void function.
So your front-end needs to be changed to:
<div>
#{
Html.RenderAction("UrunOzellikTipWidget", "Admin");
Html.RenderAction("UrunOzellikDegerWidget", "Admin");
}
</div>
The other's answer (removing the redundant ampersands) won't work because those 2 RenderAction are wrapped inside a <div />. If you remove the ampersand, they're treated as just regular HTML. It will output as:
Revise your code in FRONTEND to the following (remove the redundant ampersands from both Html.RenderAction statements).
<div>
#{ Html.RenderAction("UrunOzellikTipWidget", "Admin"); }
#{ Html.RenderAction("UrunOzellikDegerWidget", "Admin") };
</div>

Mobile upload using a different image button immediately after selecting image?

I would like to use my own .png image to trigger a
<input type="file" id="pictureCapture" accept="image/*; capture=camera" />
and then instantly upload the image to an MVC controller.
So, the first question is how to replace the input tag with a clickable image?
And second, thus far, I've only seen file upload as a 2 part process. You click the browse button, select your file, then click Upload to send the file.
How do I consolidate it so that right after you select the file, it uploads?
Is there a 3rd party control that does all this for me?
Here's what I ended up doing:
Html:
<input type="file" id="pictureCapture" accept="image/*; capture=camera" style="visibility:hidden;" />
<img src="#(Url.Content("~/Images/Mobile/Camera.png"))" />
Javascript:
<script>
$("#uploadPhotoFromCamera").click(function (e) {
e.preventDefault();
$("#pictureCapture").trigger("click");
});
$('#pictureCapture').on("change", function () {
var formdata = new FormData(); //FormData object
var fileInput = document.getElementById('pictureCapture');
//Iterating through each files selected in fileInput
for (i = 0; i < fileInput.files.length; i++) {
//Appending each file to FormData object
formdata.append(fileInput.files[i].name, fileInput.files[i]);
}
//Creating an XMLHttpRequest and sending
var xhr = new XMLHttpRequest();
xhr.open('POST', '#(Url.Action("UploadMobile", "Document"))')
xhr.send(formdata);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
alert('success');
}
}
return false;
});
</script>
Controller:
public virtual ActionResult UploadMobile()
{
List<HttpPostedFileBase> files = new List<HttpPostedFileBase>();
for (int i = 0; i < Request.Files.Count; i++)
{
files.Add(Request.Files[i]); //Uploaded file
}
// Do whatever now with your list of files
return Json("Uploaded " + Request.Files.Count + " files");
}

Making TPL Async calls from mvc controller on click of submit button

Basically I want to implement simple search functionality, whenever user enters some keyword in the text box on view and clicks submit button I want to make ASYNC calls to predefined website urls using TPL Async mechanism. When I do the same with console application it works like a charm but not with ASP.NET MVC3.
I couldn't find the reason
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
[HttpPost]
public ActionResult Index(string text)
{
string[] url = { "http://www.msnbc.com", "http://www.yahoo.com",
"http://www.nytimes.com", "http://www.washingtonpost.com",
"http://www.latimes.com", "http://www.newsday.com" };
Task<string[]> webTask = this.GetWordCounts(url, text);
string[] results = null;
try
{
results = webTask.Result;
}
catch (AggregateException e)
{
}
return View("Index", results);
}
//Taken from MSDN
Task<string[]> GetWordCounts(string[] urls, string name)
{
TaskCompletionSource<string[]> tcs = new TaskCompletionSource<string[]>();
WebClient[] webClients = new WebClient[urls.Length];
object m_lock = new object();
int count = 0;
List<string> results = new List<string>();
for (int i = 0; i < urls.Length; i++)
{
webClients[i] = new WebClient();
#region callback
// Specify the callback for the DownloadStringCompleted
// event that will be raised by this WebClient instance.
webClients[i].DownloadStringCompleted += (obj, args) =>
{
if (args.Cancelled == true)
{
tcs.TrySetCanceled();
return;
}
else if (args.Error != null)
{
// Pass through to the underlying Task
// any exceptions thrown by the WebClient
// during the asynchronous operation.
tcs.TrySetException(args.Error);
return;
}
else
{
// Split the string into an array of words,
// then count the number of elements that match
// the search term.
string[] words = null;
words = args.Result.Split(' ');
string NAME = name.ToUpper();
int nameCount = (from word in words.AsParallel()
where word.ToUpper().Contains(NAME)
select word)
.Count();
// Associate the results with the url, and add new string to the array that
// the underlying Task object will return in its Result property.
results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, name));
}
// If this is the last async operation to complete,
// then set the Result property on the underlying Task.
lock (m_lock)
{
count++;
if (count == urls.Length)
{
tcs.TrySetResult(results.ToArray());
}
}
};
#endregion
// Call DownloadStringAsync for each URL.
Uri address = null;
try
{
address = new Uri(urls[i]);
// Pass the address, and also use it for the userToken
// to identify the page when the delegate is invoked.
webClients[i].DownloadStringAsync(address, address);
}
catch (UriFormatException ex)
{
// Abandon the entire operation if one url is malformed.
// Other actions are possible here.
tcs.TrySetException(ex);
return tcs.Task;
}
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
this is my view - for now I have hard coded keyword as microsoft
#using (Html.BeginForm("Index", "Home", new { text = "Microsoft" }))
{
<input type="submit" />
}
Update: It stays forever and inside the try block of Index Post method
I would recommend you using an AsyncController for this task to avoid jeopardizing ASP.NET worker threads which is one the worst thing that might happen to an ASP.NET application => running out of worker threads. It's like running out of fuel in the middle of the desert. You most certainly die.
So let's start by writing an extension method that will allow us converting the legacy WebClient event based pattern into the new task based pattern:
public static class TaskExtensions
{
public static Task<string> DownloadStringAsTask(this string url)
{
var tcs = new TaskCompletionSource<string>(url);
var client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error != null)
{
tcs.SetException(args.Error);
}
else
{
tcs.SetResult(args.Result);
}
};
client.DownloadStringAsync(new Uri(url));
return tcs.Task;
}
}
Armed with this extension method in hand we could now define a view model that will basically reflect the requirements of our view:
public class DownloadResultViewModel
{
public string Url { get; set; }
public int WordCount { get; set; }
public string Error { get; set; }
}
Then we move on to an asyncrhonous controller that will contain 2 actions: a standard synchronous Index action that will render the search form and an asynchronous Search action that will perform the actual work:
public class HomeController : AsyncController
{
public ActionResult Index()
{
return View();
}
[AsyncTimeout(600000)]
[HttpPost]
public void SearchAsync(string searchText)
{
AsyncManager.Parameters["searchText"] = searchText;
string[] urls =
{
"http://www.msnbc.com",
"http://www.yahoo.com",
"http://www.nytimes.com",
"http://www.washingtonpost.com",
"http://www.latimes.com",
"http://www.unexistentdomainthatwillcrash.com",
"http://www.newsday.com"
};
var tasks = urls.Select(url => url.DownloadStringAsTask());
AsyncManager.OutstandingOperations.Increment(urls.Length);
Task.Factory.ContinueWhenAll(tasks.ToArray(), allTasks =>
{
var results =
from task in allTasks
let error = task.IsFaulted ? task.Exception.Message : null
let result = !task.IsFaulted ? task.Result : string.Empty
select new DownloadResultViewModel
{
Url = (string)task.AsyncState,
Error = error,
WordCount = result.Split(' ')
.Where(x => string.Equals(x, searchText, StringComparison.OrdinalIgnoreCase))
.Count()
};
AsyncManager.Parameters["results"] = results;
AsyncManager.OutstandingOperations.Decrement(urls.Length);
});
}
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return View("index", results);
}
}
Now we define an ~/Views/Home/Index.cshtml view that will contain the search logic as well as the results:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
And of course the corresponding display template that will be rendered automatically for each element of our model (~/Views/Shared/DisplayTemplates/DownloadResultViewModel.cshtml):
#model DownloadResultViewModel
<tr>
<td>#Html.DisplayFor(x => x.Url)</td>
<td>
#if (Model.Error != null)
{
#Html.DisplayFor(x => x.Error)
}
else
{
#Html.DisplayFor(x => x.WordCount)
}
</td>
</tr>
Now, since the search operation could take quite a long time your users could quickly get bored without being able to use some of the other hundredths of functionalities that your webpage has to offer them.
In this case it is absolutely trivial to invoke the Search controller action using an AJAX request and showing a spinner to inform the users that their search is in progress but without freezing the webpage allowing them to do other things (without navigating away from the page obviously).
So let's do that, shall we?
We start by externalizing the results into a partial (~/Views/Home/_Results.cshtml) without touching at the display template:
#model IEnumerable<DownloadResultViewModel>
#if (Model != null)
{
<h3>Search results</h3>
<table>
<thead>
<tr>
<th>Url</th>
<th>Word count</th>
</tr>
</thead>
<tbody>
#Html.DisplayForModel()
</tbody>
</table>
}
and we adapt our ~/Views/Home/Index.cshtml view to use this partial:
#model IEnumerable<DownloadResultViewModel>
#using (Html.BeginForm("search", null, new { searchText = "politics" }))
{
<button type="submit">Search</button>
}
<div id="results">
#Html.Partial("_Results")
</div>
and of course the SearchCompleted controller action that must now return only the partial result:
public ActionResult SearchCompleted(IEnumerable<DownloadResultViewModel> results)
{
return PartialView("_Results", results);
}
Now all that's left is to write a simple javascript that will AJAXify our search form. So this could happen into a separate js that will reference in our layout:
$(function () {
$('form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
success: function (results) {
$('#results').html(results);
}
});
return false;
});
});
Depending on whether you referenced this script in the <head> section or at the end of the body you might not need to wrap it in a document.ready. If the script is at the end you could remove the wrapping document.ready function from my example.
And the last part is to give some visual indication to the user that the site is actually performing a search. This could be done using a global ajax event handler that we might subscribe to:
$(function () {
$(document).ajaxStart(function () {
$('#results').html('searching ...');
});
});

MVC 1.0 Ajax.BeginForm() submit inside an Html.BeginForm()

I have a View for creating a new account in my application. This view starts with Html.BeginForm() and hits the right controller (Create) no problems.
I decided to add an Ajax.BeginForm() so that I could make sure an account with the same name doesn't already exist in my application.
When I click the submit using either button it goes to the same controller (Create). To try and differentiate which submit button was clicked, I put in a check to see if the request is Ajax then try to run a different code path. But Request.IsAjaxRequest() doesn't fire. What is my best bet to implement this functionality in an existing form with MS Ajax?
<% using (Html.BeginForm()) {%>
..............
<% using(Ajax.BeginForm("Echo",
new AjaxOptions() { UpdateTargetId = "EchoTarget" }))
{ %>
Echo the following text:
<%=Html.TextBox("echo", null, new { size = 40 })%>
<input type="submit" value="Echo" />
<% } %>
<div id="EchoTarget">
controller code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(User newUser)
{
if (Request.IsAjaxRequest())
{
return Content("*you hit the ajax button");
}
else
{ //regular create code here.....
}
</div>
If you insist on multiple form usage..use Javascript in a some function like this
<SCRIPT>
function InnerFormSubmitter(dataForm, actionForm) {
actionForm.innerHTML = dataForm.innerHTML;
actionForm.submit();
}
</SCRIPT>
<form name="yourButton" action="ValidateSomething" method="post"></form>
<form name="mainForm" action="SavedData" method="post">
<input type="textbox" name="text1">
<input type="textbox" name="text2">
<button name="validateUserButton" id="FormButton" onChange=
"InnerFormSubmitter (this.form, document.getElementById('yourButton'))">
</button>
</form>
Hope this helps!
Addendum on jQuery usage for your scenario:
Since you wanted a link:
Check Availability
function isValidUser(userId) {
var url = "<CONTROLLER>/<ACTION>/" + userId;
$.post(url, function(data) {
if (data) {
// callback to show valid user
} else {
// callback to show error/permission
}
});
}
And you controller should have:
[AcceptVerbs("POST")]
public bool IsValidUser(int id) {
// check availability
bool allow = CheckUser();
// if allow then insert
if (allow) {
//insert user
return true;
} else {
return false;
}
}
Further Update on jQuery:
Instead of
document.getElementById('UserIdent').value
you can use
$('#UserIdent').val();
Update on JSON usage
The JsonResult class should be used in the Controller and $.getJson function in the View.
$(function() {
$('#yourLinkOrButton').click(function() {
$.getJSON("<CONTROLLER>/GetUserAvailability/", null, function(data) {
$("#yourDivorLablel").<yourFunctionToUpdateDiv>(data);
});
});
public JsonResult GetUserAvailability()
{
//do all validation and retrieval
//return JsonResult type
}
You cannot nest forms, ever, in any HTML page, no matter how you generate the form. It isn't valid HTML, and browsers may not handle it properly. You must make the forms siblings rather than children.

Resources