Force Knockout component in Durandal page to wait for Ajax call before binding - ajax

I am trying to bind my parameter of a custom knockout component into the viewmodel with a value provided by an ajax call. However it appears the binding is taking place before the ajax call completes. Is there anyway to make sure the ajax call completes before the binding occurs? Thanks.
The view with the custom component is something like this
<section>
<mycustomcomponent params="item: item"> </mycustomcomponent>
</section>
Here are the relevant parts of the viewmodel
define(function (require) {
var Item = require('models/item');
var item;
return {
activate: function () {
var ajaxCall = $.ajax({
method: 'get',
url: 'myapicall',
success: function (data) {
item = new Item(data);
}
});
return ajaxCall;
},
item: item,
};
});

You could try wrapping the component in an if binding so that it doesn't render until item contains something valid.
<section data-bind="if: item">
<mycustomcomponent params="item: item"> </mycustomcomponent>
</section>

Related

MVC Core ajax and return result is a view

MVC Core, NET 5, not razor pages.
On a view I have three select components (bootstrap-select). I populate them via ViewModel.
"Get request -> Controller -> return View(viewModel);"
What I want...
When I changed value in any select component I do a post request (ajax) to the same controller (other method) and return view with repopulated data.
"'Post request -> Controller -> return View(changedModel);"
As I understood when I did ajax request I should handle it result in success and other cases.
What I should to do to reload page with new data?
Is it possible to achive this with this approach?
Yes, this is possible and you do not need to reload the page, just append the returned html to wherever you want it.
$.ajax({
type: "POST",
url: {your_url},
dataType: "html",
success: function (html) {
$("#someDiv").html(html);
}
});
What I should to do to reload page with new data?
If the post action return the same view as the get action and you want to reload the whole page, I think there is no need to use ajax. You can just redirect to post action with a form submission. If the view returned by the post action is a partialview you want render to the current view, you can use it like that in #cwalvoort answer.
Based on advices of cwalvoort and mj1313
I did:
Render main page with partials. ViewModel transfered to a partial as a parameter
On main page I added eventListners to controls with JS.
When control changes - ajax request to backend happens Controller/GetPartialView
Result from ajax replace html in partial section
Programmatically show needed components, re-add eventListners
PS Really need to learn Blazor or UI Framework :)
Code samples:
// JS
document.addEventListener("DOMContentLoaded", function (event) {
BindSelectActions();
});
function BindSelectActions() {
$('#selectGroups').on('hidden.bs.select', DoPartialUpdate);
$('#selectCompanies').on('hidden.bs.select', DoPartialUpdate);
$('#selectPeriods').on('hidden.bs.select', DoPartialUpdate);
}
function DoPartialUpdate(e, clickedIndex, isSelected, previousValue) {
// ToDo: Implement common script with "CallBackend" function
$.ajax({
type: "POST",
url: 'https://localhost:44352/TestController/TestGetPartial',
// no data its a stub at the moment
// data: $('#form').serialize(),
success: function (data, textStatus) {
$("#testControls").html(data);
$('#selectGroups').selectpicker('show');
$('#selectCompanies').selectpicker('show');
$('#selectPeriods').selectpicker('show');
BindSelectActions();
}
});
}
// Controllers
[HttpGet]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public async Task<IActionResult> Main()
{
// ViewModel = _helper -> _mediator -> query -> context
return await Task.Run(() => View(new TestViewModel()));
}
[HttpPost]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public IActionResult TestGetPartial(TestViewModel model)
{
// ViewModel = _helper -> _mediator -> query -> context
var result = new TestViewModel();
result.IsPageReload = "yes";
result.TestCollection = new string[] { "A", "B", "C" };
result.Companies = new List<SelectListItem> { new SelectListItem { Value = "999",
Text = "Test" } };
// ModelState.Clear();
return PartialView("_TestPartial", result);
}
// Main and partial views
#model TestViewModel
#{
ViewData["Title"] = "Test";
}
<div id="testControls">
#await Html.PartialAsync("_TestPartial", Model)
</div>
#section Scripts {
<script type="text/javascript" src="~/js/test.js" asp-append-version="true">
</script>
}
#model TestViewModel
<form>
<div class="d-flex flex-row justify-content-between mt-4">
<div><select id="selectGroups" asp-for="Groups" asp-items="Model.Groups"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Group"></select></div>
<div><select id="selectCompanies" asp-for="Companies" asp-items="Model.Companies"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Company"></select></div>
<div><select id="selectPeriods" asp-for="Periods" asp-items="Model.Periods"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Period"></select></div>
<div><button type="button" class="btn btn-outline-dark">Import</button></div>
</div>
</form>
<div>
#{
if (null != Model.TestCollection)
{
foreach (var item in Model.TestCollection)
{
<p>#item</p>
<br>
}
}
}
</div>

CORE 2 MVC Ajax redirect to display a view

I have an application that uses the jQuery Datatable and I want to click on a row, pick up the id, and then bring up a view that allows for editing of that view and updating the underlying database.
Ajax gets me to the controller-action that for the edit view but I can't get the view itself to display. Instead, the controller action just returns to ajax. I've tried numerous tactics with no joy. Here is a simple example based upon a standard CORE template:
#section scripts{
<script>
$(document).on('click', 'button.number', function () {
alert($(this).val());
$.ajax({
method: 'GET',
url: '#Url.Action("About", "Home")'
});
});
</script>
}
<h3>Home Page</h3>
<div>
<button href="#" type="button" class="number" id="one" value="1">1</button>
<button href="#" type="button" class="number" id="two" value="2">2</button>
</div>
Running the debugger shows that About action is called OK but the view isn't rendered - it just returns to ajax. I've tried all sorts of redirection but any "return" just goes back to ajax.
Is there away around this or perhaps a better way to get from the JS to the controller-action? Thanks
EDIT:
Batuhan gets the credit for his solution but I'm re-posting it to clean up a little syntax and add the parameter passing that was my initial goal.
$(document).on('click', 'button.number', function () {
var id = $(this).val();
alert(id);
$.ajax
({
method: 'GET',
url: '#Url.Action("About", "Home")',
}).success(function (result) {
window.location.href = '/home/about/' + id;
});
});
And here is Home Controller for the About Action:
public IActionResult About(int id)
{
string parm2 = id.ToString();
ViewBag.msg = parm2;
return View();
}
And the About page:
#{
ViewData["Title"] = "About";
}
<p>
<h1> #ViewBag.msg </h1>
</p>
All works as initially hoped for!
$(document).on('click', 'button.number', function () {
alert($(this).val());
$.ajax({
method: 'GET',
url: '#Url.Action("About", "Home")'
}).success: function(result){
///this line
window.href='redirect url';
}});;
});
this is a solution cause you cant redirect from ajax call. it returns The view in html form So if you want to postback you needto use window.href="url";

How to load Different Partial Views on the same div by radio button selection?

enter code here
*MainView.cshtml*: #RadioButtonFor(m=>m.registeras,Individual) #RadioButtonFor(m=>m.registeras,BusinessEntity) <div id="loadpartial"> </div>
I have a register form in which User can register as Individual or Business entity. I kept two radio buttons.
If user selects Individual Radio Button, then that partial view should be loaded. if user selects Business entity radio Button then second partial view should be loaded on the same div.
I am new to asp.net mvc4 razor. Can someone please give the sample code.
You will have to use jQuery in order to make ajax calls.
First reference jQuery at the bottom of your page.
in your controller, define and implement a method which returns a partial view.
[HttpGet]
public ActionResult GetRegisterForm(int registeras)
{
if(registeras == Individual)
{
return PartialView("IndividualPartialViewName");
}
else
{
return PartialView("BusinessPartialViewName");
}
}
Now in your view, you can call the above action using ajax.
<script type="text/javascript">
$(function(){
$("[name=registeras]").on('change', function(){
var $radio = $(this);
$.ajax({
url:'#Url.Action("GetRegisterForm", "ControllerName")',
data: { registeras = $radio.val() }
type: 'GET',
success: function(data){
$("#loadpartial").html(data);
}
});
});
</script>

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?

Is there a way to use AJAX on a DropDownList changed event to dynamically modify a partial view on a page?
My main page has a DropDownList (DropDownListFor) and a partial view which ONLY contains a list of "items". The items shown in this partial view are dependent upon the item selected in the DropDownList. There's a 1 to many relationship between the DropDownList item and the items in the partial view. So, when the user changes the value of the DropDownList, the content in the partial view will dynamically change to reflect the item selected in the DropDownList.
Here's my DropDownList:
<div data-role="fieldcontain">
Choose Capsule:<br />
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules" })
<br />
</div>
Here's my Partial View declaration on the same page:
<div data-role="fieldcontain">
#Html.Partial("_FillerPartial", Model.Fillers)
</div>
I'm not very familiar with Ajax, but looking at other examples, here's what I have for my Ajax:
$(document).ready(function () {
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
alert("server returned: " + data);
}
});
});
});
And finally, here's a screenshot of what's going on. By changing the "Choose Capsule" drop down list, I want the Filler list to update dynamically:
You can load the drop down list as a partial view from the controller using ajax.
The controller code:
[HttpGet]
public virtual ActionResult GetFillersByCapsule(string cappk)
{
var model = //Method to get capsules by pk, this returns a ViewModel that is used to render the filtered list.
return PartialView("PartialViewName", model);
}
The main view html:
<div id="filteredList">
</div >
The partial view
#model IEnumerable<MyCapsuleModel>
foreach (var x in Model)
{
//Render the appropriate filtered list html.
}
And you can load the filtered list using ajax:
$('#ddlCapsules').change(function () {
// make ajax call to modify the filler list partial view
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
$("#filteredList").empty();
$("#filteredList").html(data);
}
});
});
Hope this helps.
You can't update the partial, per se, because the partial will never be rendered again without a page reload. Once you receive the HTML, ASP is done, you're on your own at that point.
What you can do, of course, is switch out the content of a particular div or whatever using JavaScript. Your example in particular screams Knockout, so that's what I would recommend using.
Change your HTML to add a data-bind to your containing div:
<div data-role="fieldcontain" data-bind="foreach: filler">
<button data-bind="text: name"></button>
</div>
And your DropDownList:
#Html.DropDownListFor(x => x.CapsuleFK, new SelectList(Model.Capsules, "pk", "name", "pk"), new { id = "ddlCapsules", data_bind = "event: { change: updateFillers }" })
Then, some JavaScript:
var FillersViewModel = function () {
var self = this;
self.fillers = ko.observableArray([]);
self.updateFillers = function () {
var selection = $('#ddlCapsules').val();
var dataToSend = { cappk: selection };
$.ajax({
url: 'Process/GetFillersByCapsule',
data: { cappk: dataToSend },
success: function (data) {
self.fillers(data.fillers) // where `fillers` is an array
}
});
}
}
var viewModel = new FillersViewModel();
ko.applyBindings(viewModel);
This is a very simplistic example, and you'll need to do some more work to make it do everything you need it to do in your scenario, but the general idea is that every time the dropdown list is changed, Knockout will call your updateFillers method, which will execute the AJAX and put new data into the fillers observable array. Knockout automatically tracks changes to this array (hence the "observable" part), so an update is automatically triggered to any part of your page that relies on it. In this scenario, that's your div containing the buttons. The foreach binding will repeat the HTML inside for each member of the array. I've used a simple button element here just to illustrate, but you would include the full HTML required to create your particular button like interface. The text binding will drop the content of name in between the opening and closing tag. Refer to: http://knockoutjs.com/documentation/introduction.html for all the binding options you have.
There's much more you could do with this. You could implement templates instead of hard-coding your HTML to be repeated in the foreach. And, you can use your partial view to control the HTML for this template. The important part is that Knockout takes the pain out of generating all this repeating HTML for you, which is why I recommend using it.
Hope that's enough to get you started.

MVC3 Ajax call to Controller

Is there anyway to submit a form but have it remain on the page?
Right now I'm displaying a table of objects, but each row has an editable value with each row in its own Ajax form but when I click the update button it goes to the method alright but the whole page changes.
Is there anyway to submit a form but have it remain on the page?
Of course, you could use AJAX:
#using (Html.BeginForm())
{
... some form input fields
<input type="submit" value="Go" />
}
and then unobtrusively AJAXify this form in a separate file:
$(function() {
$('form').submit(function() {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function(result) {
// TODO: handle the results of the AJAX call
}
});
return false;
});
});
and to avoid writing all this javascript code you may take a look at the excellent jquery.form plugin:
$(function() {
$('form').ajaxForm(function(result) {
// TODO: handle the results of the AJAX call
});
});
Another alternative is to use the ASP.NET MVC 3 Ajax.BeginForm helper:
#using (Ajax.BeginForm(new AjaxOptions { OnSuccess = "success" }))
{
... some form input fields
<input type="submit" value="Go" />
}
and then have a success handler in javascript:
function success(result) {
// TODO: handle the results of the AJAX call
}
you will also need to include the jquery.unobtrusive-ajax.js script in addition to jquery to your page if you want to use the Ajax.* helpers.

Resources