So, I have web application for currency exchange. What I need is to get the result of conversion without reloading the page. In this application I get data from api. After submiting the form page starts to reload and calls HttpGet method again. I get exception because of it. Is there any way to convert currency and do not reload the page?
Model
public class ExchangeRate
{
[JsonProperty("rates")]
public Dictionary<string, double> Rates { get; set; }
[JsonProperty("base")]
public string Base { get; set; }
[JsonProperty("date")]
public DateTimeOffset Date { get; set; }
}
Controller
public class HomeController : Controller
{
[HttpGet]
public async Task<ActionResult> Index()
{
ExchangeRate curencyInfo = new ExchangeRate();
using (HttpClient client = new HttpClient())
{
curencyInfo = await client.GetFromJsonAsync<ExchangeRate>("https://api.exchangeratesapi.io/latest?base=USD");
}
return View(curencyInfo);
}
[HttpPost]
public ActionResult Index(decimal fromCurrency, decimal toCurrency, decimal fromValue)
{
var toValue = toCurrency / fromCurrency * fromValue;
decimal result = Math.Round(toValue, 2);
ViewBag.toValue = result;
return View();
}
}
View
#model WebCurrencyConverter.Models.ExchangeRate
#{
ViewData["Title"] = "Currency Converter";
}
<h1>Currency Converter</h1>
<form method="post">
<select name="fromCurrency">
#foreach (var itemFrom in Model.Rates)
{
<option value="#itemFrom.Value">#itemFrom.Key</option>
}
</select>
<input type="hidden" value="#Model.Rates" />
<select name="toCurrency">
#foreach (var itemTo in Model.Rates)
{
<option value="#itemTo.Value">#itemTo.Key</option>
}
</select>
<input type="number" name="fromValue" step="any" />
<input type="number" name="toValue" value="#ViewBag.toValue" />
<input type="submit" class="btn btn-success" value="Convert" />
</form>
I get exception because of it. Is there any way to convert currency and do not reload the page?
To avoid reloading the page,I think you could use ajax to post data.
Here is a whole working demo:
View:
#model ExchangeRate
#{
ViewData["Title"] = "Currency Converter";
}
<h1>Currency Converter</h1>
<form method="post">
<select name="fromCurrency">
#foreach (var itemFrom in Model.Rates)
{
<option value="#itemFrom.Value">#itemFrom.Key</option>
}
</select>
<input type="hidden" value="#Model.Rates" />
<select name="toCurrency">
#foreach (var itemTo in Model.Rates)
{
<option value="#itemTo.Value">#itemTo.Key</option>
}
</select>
<input type="number" name="fromValue" step="any" />
<input type="number" name="toValue" /> //change here.....
//change the type to button and add the id for button
<input type="button" class="btn btn-success" id="convert" value="Convert" />
</form>
Js in View:
#section Scripts
{
<script>
$("#convert").click(function () {
console.log($('form').serialize());
$.ajax({
url: "/Home/Index",
type: "Post",
data: $('form').serialize(),
success: function (data) {
console.log(data.result);
$('input[name="toValue"]').val(data.result);
}
})
})
</script>
}
Controller:
[HttpGet]
public async Task<ActionResult> Index()
{
ExchangeRate curencyInfo = new ExchangeRate();
curencyInfo.Rates = new Dictionary<string, double>() { };
curencyInfo.Rates.Add("US", 1);
curencyInfo.Rates.Add("Euro", 0.82);
return View(curencyInfo);
}
[HttpPost]
public JsonResult Index(decimal fromCurrency, decimal toCurrency, decimal fromValue)
{
var toValue = toCurrency / fromCurrency * fromValue;
decimal result = Math.Round(toValue, 2);
return Json(new { result = result });
}
Result:
Related
I have a relatively simple form that's posting to a controller, yet the model is coming through as null every time and I don't understand why. I'm using Umbraco CMS (so please ignore any Umbraco references if they're not relevant) and jquery combined with an image plugin (Filepond) to post the data. This is my model:
public class PropertyViewModel: PublishedContentWrapped
{
public PropertyViewModel(IPublishedContent content, IPublishedValueFallback publishedValueFallback) : base(content, publishedValueFallback)
{
this.Countries = GetCountries();
}
[Required]
public string Country { get; set; }
[Required]
public string DisplayName { get; set; }
[Required]
public string Summary { get; set; }
[Required]
public string Description { get; set; }
[Required(ErrorMessage = "Please select at least one image")]
public List<IFormFile> Images { get; set; }
public SelectList Countries { get; set; }
public SelectList GetCountries()
{
List<string> countryNames = Bia.Countries.Iso3166.Countries.GetAllActiveDirectoryNames();
var countries = new List<SelectListItem>();
foreach (var country in countryNames)
countries.Add(new SelectListItem { Text = country, Value = country });
return new SelectList(countries, "Text", "Value");
}
}
Here is the controller:
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public async Task<IActionResult> HandleAddProperty(PropertyViewModel model)
{
if (ModelState.IsValid == false)
{
return CurrentUmbracoPage();
}
// Carry on execution..
}
Finally, here is my view. I should mention that model is a new instance of the PropertyViewModel class:
#using (Html.BeginUmbracoForm<PropertySurfaceController>("HandleAddProperty", null, new { #id = "form-add" }))
{
<div asp-validation-summary="All" class="text-danger"></div>
<div class="mb-3">
<select asp-for="#Model.Country" asp-items="Model.Countries" class="form-select">
<option value="">Select country</option>
</select>
<span asp-validation-for="#Model.Country" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="#Model.DisplayName" class="form-label"></label>
<input asp-for="#Model.DisplayName" class="form-control" aria-required="true" />
<span asp-validation-for="#Model.DisplayName" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="#Model.Summary" class="form-label"></label>
<textarea asp-for="#Model.Summary" class="form-control" aria-required="true"></textarea>
<span asp-validation-for="#Model.Summary" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="#Model.Description" class="form-label"></label>
<textarea asp-for="#Model.Description" class="form-control" aria-required="true"></textarea>
<span asp-validation-for="#Model.Description" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<input type="file" class="filepond" id="file" name="filepond" multiple data-max-file-size="5MB" data-max-files="10" accept="image/png, image/jpeg, image/gif">
</div>
<button type="submit" class="btn btn-primary" id="submit">Submit</button>
}
<script>
$(document).ready(function(e){
FilePond.registerPlugin(
FilePondPluginImageResize,
FilePondPluginFileValidateSize
);
var pond = FilePond.create(
document.querySelector('#file'), {
allowMultiple: true,
instantUpload: false,
allowProcess: false,
imageResizeTargetWidth: 1280,
imageResizeUpscale: false,
imageResizeMode: 'contain'
});
$("#form-add").submit(function (e) {
e.preventDefault();
var formdata = new FormData(this);
// append FilePond files into the form data
var pondFiles = pond.getFiles();
for (var i = 0; i < pondFiles.length; i++) {
formdata.append('Images', pondFiles[i].file);
}
console.log('formdata', formdata);
$.ajax({
url: "/umbraco/surface/PropertySurface/HandleAddProperty",
data: formdata,
dataType: 'JSON',
processData: false,
contentType: false,
method:"post"
}).done(function (response) {
// todo
});
})
});
</script>
When I inspect in Chrome to see what data is being sent to the server I can see the following:
So I can see the fields are matching the model, yet it's still coming through as null. I can't figure out where it's failing.
I've tried using [FromBody] and [FromForm] with the controller parameter, but it made no difference.
Is anyone able to spot where I'm going wrong?
I think the second parameter in BeginUmbracoForm is supposed to be the model, not null. So:
#using (Html.BeginUmbracoForm<PropertySurfaceController>("HandleAddProperty", new { #id = "form-add" }))
{ ... }
I have an app in which I post some JSON data to my server and then create an object that will later be added to a database.This is done by the "Save" method in my "SendItemsController":
[Route("SendItems/Save")]
[ApiController]
public class SendItemsController : Controller
{
private AppDbContext _db;
public SendItemsController(AppDbContext db)
{
_db = db;
}
[HttpPost]
[Consumes("application/json")]
public async Task<IActionResult> Save([FromBody] ShoppingCart s)
{
await _db.ShoppingCarts.AddAsync(s);
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
[HttpGet("~/ThankYou/Index")]
public IActionResult Index()
{
return View();
}
}
After the object is added to the database I try to redirect the client to a "ThankYou" page.
When first launched when I press my order button on the "Cart" page it redirects the client to the "ThankYou" page without firing the "Save" method, but if I go back from the "ThankYou" page to the "Cart" page and hit the button again, the method is fired, the object is added to the database and the client is redirected to the "ThankYou" page, just as it should.My question is what should I change to my code in order to make it fire from the first time, not after going back and hitting the order button again.
I will provide the code that I have written.
Here is the javascript that I use in order to form my JSON object and then POST it to my server:
var orderB = document.getElementById("orderB");
orderB.addEventListener("click", function () {
var inputName = document.getElementById("inputName").value;
var inputAddress = document.getElementById("inputAddress").value;
var inputMail = document.getElementById("inputMail").value;
var auxArray = [];
for (var i = 0; i < productsAux.length; i++) {
if (productsAux[i]!="") {
auxArray[i-1] = { "productName": productsAux[i].titlu, "productPrice": productsAux[i].pret, "quantity": localStorage.getItem(productsAux[i].titlu) };
}
}
var shoppingCart = {
productList: auxArray,
clientName: inputName,
clientAddress: inputAddress,
clientMail: inputMail
};
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "senditems/save",
contentType: "application/json;charset=utf-8",
})
})
And here is the html for my form that I use to gather the name,address and email from the client :
<div class="form-group row">
<div class="col-4">
<label id="clientName"></label>
</div>
<div class="col-6">
<input id="inputName" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientAddress"></label>
</div>
<div class="col-6">
<input id="inputAddress" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label id="clientMail"></label>
</div>
<div class="col-6">
<input id="inputMail" type="text" />
</div>
</div>
<div class="form-group row">
<div class="col-3 offset-4">
<button class="btn btn-primary " id="orderB" asp-controller="SendItems" action="Save">ORDER</button>
</div>
</div>
</form>
Firstly,I am not sure if you have provided the whole ajax,because an ajax requested action will not let you redirect in the backend.You could only redirect it in your ajax function.
Secondly,you have added the onclick event,no need to add asp-controller tag helper it would render wrong formaction.
Thirdly,the item i starts with 0 but the index of auxArray starts with -1,the product array may not pass to the backend successfully.
At last,the ajax url should be:/senditems/save.
Here is a working demo like below:
Model:
public class ShoppingCart
{
public string clientName { get; set; }
public string clientAddress { get; set; }
public string clientMail { get; set; }
public List<Product> productList { get; set; }
}
public class Product
{
public string productName { get; set; }
public int productPrice { get; set; }
public int quantity { get; set; }
}
View:
<form>
//....
<div class="form-group row">
<div class="col-3 offset-4">
<button class="btn btn-primary" id="orderB" type="button">ORDER</button>
</div>
</div>
</form>
#section Scripts
{
<script>
var orderB = document.getElementById("orderB");
orderB.addEventListener("click", function () {
var inputName = document.getElementById("inputName").value;
var inputAddress = document.getElementById("inputAddress").value;
var inputMail = document.getElementById("inputMail").value;
var auxArray = [];
for (var i = 0; i < 1; i++) {
auxArray[i] = { "productName": "aaaa", "productPrice": 34, "quantity": 3 };
}
var shoppingCart = {
productList: auxArray,
clientName: inputName,
clientAddress: inputAddress,
clientMail: inputMail
};
$.ajax({
type: "POST",
data: JSON.stringify(shoppingCart),
url: "/senditems/save", //add `/`
contentType: "application/json;charset=utf-8",
success: function (res) {
window.location.href = res; //redirect like this
}
})
})
</script>
}
Controller:
[Route("SendItems/Save")]
[ApiController]
public class SendItemsController : Controller
{
[HttpPost]
[Consumes("application/json")]
public async Task<IActionResult> Save([FromBody] ShoppingCart s)
{
return Json("YourRedirectUrl");
}
}
Result:
I am creating a web app in which I need to get the value of my public Dictionary<string, string> KeyValuePairs { get; set; } in post method
here is how my code looks,
My model -> public Dictionary<string, string> KeyValuePairs { get; set; }
the above property is included in my model
#{
var index = 0;
foreach (var item in Model.KeyValuePairs)
{
<input type="hidden" value="#item.Key" name="#Model.KeyValuePairs.ElementAt(index).Key" />
<input type="hidden" value="#item.Value" name="#Model.KeyValuePairs.ElementAt(index).Value" id="#index" />
index++;
}
}
I am storing all the key value of Dictionary<string, string> but still showing as empty in my controller post event,
I also Tried Like below
#foreach (KeyValuePair<string, string> kvp in Model.KeyValuePairs)
{
<input type="hidden" name="KeyValuePairs[#index].key" value="#kvp.Key" />
<input type="hidden" name="KeyValuePairs[#index].Value" value="#kvp.Value" />
index++;
}
What I need to do to get the Dictionary in Post
Actually name="#Model.KeyValuePairs.ElementAt(index).Key" is fetching the value. It should be name="Model.KeyValuePairs[#index].Key" then it will bind data to model.
Checkout my below code to understand more clearly.
Model
public class KeyValuePairs {
public Dictionary<string, string> DictList { get; set; }
}
Controller
[HttpPost]
public ActionResult PassDictionary(KeyValuePairs model)
{
return RedirectToAction("PassDictionary");
}
View
#model Project.Web.Models.KeyValuePairs
#using (Html.BeginForm("PassDictionary", "ControllerName", FormMethod.Post, new { })) {
// I have changed foreach to forloop so no need to declare index
for (int i = 0; i < Model.DictList.Count; i++) {
<input type="hidden" value="#Model.DictList.ElementAt(i).Key" name="Model.DictList[#i].Key" />
<input type="hidden" value="#Model.DictList.ElementAt(i).Value" name="Model.DictList[#i].Value" />
}
<button type="submit" value="Submit">Submit</button>
}
PeriodFrom = 05/10/2016
PeriodTo = 06/10/2016
Above properties date format is dd/mm/yyyy as you can see from the below screen shot.
However when i click on the submit button, the values are copied to a view model.
PeriodFrom becomes 10/05/2016 and PeriodTo becomes 10/05/2016
The 10 becomes the day and the 5 becomes the month. Not sure why this is happening. Could someone please advise ?
Startup
var supportCultures = new[]
{
new CultureInfo("en-GB")
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-GB"),
SupportedCultures = supportCultures,
SupportedUICultures = supportCultures
});
View
<form asp-controller="BragManagement" asp-action="Export" method="get" role="form">
<input type="hidden" asp-for="#Model.PeriodFrom" />
<input type="hidden" asp-for="#Model.PeriodTo" />
<input type="hidden" asp-for="#Model.BragValueTitle" />
<button type="submit" class="btn btn-pink">Export</button>
</form>
Method
[HttpGet]
public IActionResult Export(UserVoteDetailSearchViewModel model)
{
var result = _userRepository.GetAllUserVoteDetails(model);
_reportService.GenerateReport(result);
return View();
}
View model
public class UserVoteDetailSearchViewModel
{
public DateTime? PeriodFrom { get; set; }
public DateTime? PeriodTo { get; set; }
public string BragValueTitle { get; set; }
public List<UserVoteDetail> UserVoteDetailList { get; set; }
}
We are making a movie rating web application but we come across the error Object reference not set to an instance of an object. even though we get that error when we navigate back to the ratings page the rating got added.
Contoller:
public ActionResult RateMedia(string Item, int Rate)
{
PopMediaDDL();
var userStore = new UserStore<ApplicationUser>(ldb);
var manager = new UserManager<ApplicationUser>(userStore);
var user = manager.FindById(User.Identity.GetUserId());
MediaRating rate = new MediaRating();
rate.Title = ldb.MediaData.First(c => c.MediaName == Item);
rate.Rating = Rate;
rate.RateFor = user;
ldb.MediaRatingData.Add(rate);
ldb.SaveChanges();
return View();
}
Model:
public class MediaRating
{
[Key]
public int MediaRatingID { get; set; }
public virtual ApplicationUser RateFor { get; set; }
public virtual Media Title { get; set; }
public int Rating { get; set; }
}
View:
#using CollectionCompanion.Extensions
#using CollectionCompanion.Models;
#model CollectionCompanion.Models.UserCollectionItem
<h2>Rate Media!</h2>
<hr />
#using (Html.BeginForm())
{
<div style="width:80%;">
<div id="AddColItem">
#Html.AntiForgeryToken()
#Html.TextBoxFor(m => m.Item, new { #id = "MediaItem",#style= "color:black;", #name = "MediaItem", #class = "form-control" })
</div>
<div id="AddColDD">
<select id="Rate" name="Rate">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</div>
<div id="AddColBTN">
<input type="hidden" name="UserCollection" value="#ViewBag.UserCollectionID" />
<button type="submit" class="btn btn-default btn-info"><span class="glyphicon glyphicon-plus"></span> Add</button>
</div>
</div>
}
#foreach (MediaRating rating in ViewBag.Ratings)
{
<div>
<div style="width:50%;">
#rating.Title.MediaName
</div>
<div style="width:50%">
#rating.Rating
</div>
</div>
}
<script type="text/javascript">
$("#MediaItem").autocomplete({
change: function (event, ui) { },
source: "../../Media/GetMediaResult/",
minLength: 2
}
);
</script>
You are returning the view without a model at the end of your controller action:
return View();
I suspect that you are getting a null reference exception because you're not providing the model nor the ViewBag required to populate the View. It should look similar to the HttpGet controller action as that is providing everything required to build the View in the first place.