How to call AngularJS function after partial postback (from ascx page) in ASP.Net inside an UpdatePanel. Initially I call angular function on ng-init. But after the partial postback, the function is not called. How could I call the function?
Function name is BindLeadGridHeader. Here is my Angular JS code:
.controller('CtrlSalesNav', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
//function for Bind Module Name Drop Down Created By :Prashant Kumar OnDate:21.04.2017
var UserId = sessionStorage.CurrentUserId;
var CurrentModuleName = 'Lead';
$scope.AllHeader = '';
//code for bind all header to table
$scope.BindLeadGridHeader = function () {
$http.get(WebApiUrl + "api/GetAllLeadHeader?UserId=" + UserId + "&ModuleName=" + CurrentModuleName).then(function (response) {
alert('Header bind call');
$scope.AllHeader = response.data.Table;
Calling code on ascx page inside UpdatePanel:
<div class="lead_noTopMenu" id="divLeadGrid" ng-controller="CtrlSalesNav" ng-cloak>
<div class="row" style="margin-top: 90px;" data-ng-init="BindLeadGridHeader();">
<!-- Search FORM-->
<div class="row row1" id="search" style="display: none;">
<div class="col-md-12">
<div class="tabbable tabbable-custom">
<ul class="nav nav-tabs">
You probably should be using an angular directive or component. There's a 3rd callback on promises that's rarely used, called notify, that might work for you. It's called while the promise is waiting to be resolved.
Related
How do you get dynamically loaded tabs to work in ASP.Net Core MVC?
I have a simple Index.cshtml that uses bootstrap tabs to create two tabs from the a tags on the page. (To test out options, I first copied from https://qawithexperts.com/article/asp.net/bootstrap-tabs-with-dynamic-content-loading-in-aspnet-mvc/176)
There is a click event on each tab that uses $.ajax() to call the controller and then set the html of the appropriate div.
I have a model with one field, a string that is required.
I have the create view that Visual Studio created.
When I run it and click the first tab, the controller returns PartialView("FirstTabCreate") and loads into the div and everything looks great.
The problem is when clicking the "Create" button.
The controller method checks if IsValid on the ModelState. If not, here is where I run into a problem. If I return the partial view and the model that was passed in I see my validation errors as expected but because I returned the partial view, I lose my tabs. If I return the main view (Index) then the javascript reloads my partial view and has lost the ModelState at that point.
I am not sure what to return so that this works. I have seen lots of examples online that use dynamically loaded tabs but none of them have models or validation.
Code below:
Index Page
#model FirstTab
<!-- Tab Buttons -->
<ul id="tabstrip" class="nav nav-tabs" role="tablist">
<li class="active">
Submission
</li>
<li>
Search
</li>
</ul>
<!-- Tab Content Containers -->
<div class="tab-content">
<div class="tab-pane active" id="FirstTab">
</div>
<div class="tab-pane fade" id="SecondTab">
</div>
</div>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$('#tabstrip a').click(function (e) {
e.preventDefault();
var tabID = $(this).attr("href").substr(1);
$(".tab-pane").each(function () {
console.log("clearing " + $(this).attr("id") + " tab");
$(this).empty();
});
$.ajax({
url: "/#ViewContext.RouteData.Values["controller"]/" + tabID,
cache: false,
type: "get",
dataType: "html",
success: function (result) {
$("#" + tabID).html(result);
}
});
$(this).tab('show');
});
$(document).ready(function () {
$('#tabstrip a')[0].click();
});
</script>
FirstTabCreate View
#model WebApplication1.Models.FirstTab
<h4>FirstTab</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="FirstTabCreate">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
Model
using System.ComponentModel.DataAnnotations;
namespace WebApplication1.Models
{
public class FirstTab
{
[Required()]
public string FirstName { get; set; }
}
}
Controller
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using WebApplication1.Models;
namespace WebApplication1.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public ActionResult FirstTab()
{
return PartialView("FirstTabCreate");
}
public ActionResult FirstTabCreate(FirstTab model)
{
if (!ModelState.IsValid)
{
return View("FirstTabCreate", model);
}
return Content("Success");
}
public ActionResult SecondTab()
{
return PartialView("_SecondTab");
}
}
}
I don't like it but to get it to work, when I click Save, in the Controller method I check if the ModelState is valid. If not, I put the keys and values into a list of custom class and then put that list in the cache. When the child partial view loads it checks to see if there is anything in the cache and if so, parses it back out and uses ModelState.AddModelError().
It's not pretty but it does allow the validation to work.
try to add jquery validation scripts in your code
delete this
<script src="~/lib/jquery/dist/jquery.min.js"></script>
and use this instead
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Add below code to your #section Scripts
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
<script>
$.validator.setDefaults({
ignore: []
});
</script>
}
Note: do not add the above inside $(document).ready()
I have a small angular app that makes an api call based on a month/year from a drop down list in asp. It is meant for that api call to be made whenever year or month drop down lists are changed.
The first/original load works just fine. According to the debugger on any change I'm hitting the api on the change, and getting a return. The entire "card-widget"/ChartController div is disappearing (even with css properties commented out).
My ASP code:
<div id="card">
<div>
</div>
<div id="card-widget" ng-app="ChartApp" ng-controller="ChartController" style="width:350px; height: 350px;">
<div>
<asp:DropDownList ID="lstMonth" runat="server" ng-model="month" ng-change="updateChart()"></asp:DropDownList>
<asp:DropDownList ID="lstYear" runat="server" ng-model="year" ng-change="updateChart()"></asp:DropDownList>
</div>
<div>
<canvas id="Chart" height="350" width="350"></canvas>
</div>
</div>
<div id="card-widget-fail" style="width: 350px; height: 100px;">
<label>No chart</label>
</div>
</div>
My Angular code:
var app = angular.module("ChartApp", []);
app.controller('ChartController', function ($scope, $http) {
$scope.updateChart = function () { getChart() };
var dataChart = document.getElementById("Chart").getContext('2d');
var year = document.getElementById("<%=lstYear.ClientID %>");
var month = document.getElementById("<%=lstMonth.ClientID %>");
getChart();
function getChart() {
//api call to load chart data based off month.options[year.selectedIndex].text & year.options[year.selectedIndex].text
}
});
The reason getChart() is not being called is because it's not present on the $scope element. Use $scope.getChart = function() { ... } instead. I recommend reading this documentation page, specifically the part "Scope as Data-Model".
So I have a div, in which I have an a element. I want the other div to Render another page (RenderPage) as soon as the a element in the other div is clicked.
<div id="Left" style="width:29.49%; height:100%; border-style:solid; border-color:darkgray;">
<h1 id="Pages"> Articles </h1><br />
<a OnClick="LoadUE()">UE</a>
<a></a>
<script>
function LoadUnity() {
}
function LoadUE() {
document.getElementById("Body").innerHTML = #{RenderPage("Bottom.cshtml")};
}
</script>
</div>
<div id="Body" style="width:69.49%; height:100%;">
</div>
The RenderPage method only works on the server when the page is first executed. If you want to load partials in ASP.NET Web Pages (which is what you are using) from client script, you should remove the leading underscore from the file name and then create an AJAX request to load it. Here's an example that uses Fetch:
#section scripts{
<script>
function loadUE() {
fetch('/bottom')
.then((response) => {
return response.text();
})
.then((result) => {
document.getElementById('body').innerHTML = result;
});
});
</script>
}
As a side note, the ASP.NET Web Pages framework is pretty much dead. If you are just learning and have a choice, you should use Razor Pages instead: https://www.learnrazorpages.com/
I want send cod to controller and return array
When pressing a li you have to send a code to the controller, in this case I am setting the example 7. Once the code has arrived at the controller I will have a list that I have to show in a ng-repeat in table
SCRIPT
<script type="text/javascript">
var app = angular.module('myApp', [])
app.value('studentInfo', [
{ id: 1, name: 'Mahedee Hasan', credit: 20, semester: '8th' },
{ id: 3, name: 'Enamul Haque', credit: 15, semester: '7th' }
]);
app.controller('myCtrl', ['$scope', 'studentInfo', function ($scope, studentInfo, $http, $window) {
$scope.myClickList = function () {
$scope.studentInfo = studentInfo;
};
var Cod = "7";
$scope.myDataCountry = [];
$scope.ButtonCountry = function (Cod) {
$http.
post("/Country/Angular", { CodH: Cod }).success(function (result) {
$scope.myDataCountry = result;
});
};
}]
);
</script>
VIEW
<li><a data-toggle="tab" href="#calificaciones" ng-click="ButtonCountry ()"><span>Country</span></a></li>
<div ng-app="myApp" ng-controller="myCtrl">
<table class="table">
<tr>
<th>ID</th>
<th>Country</th>
</tr>
<tr ng-repeat="C in myDataCountry">
<td>{{C.ID}}</td>
<td>{{C.Country}}</td>
</tr>
</table>
</div>
CONTROLLER
public JsonResult Angular(string codCountry)
{
var country = (from a in dbCountry.Country
where a.CodPersona == codCountry
select a.Country).ToList();
return Json(country , JsonRequestBehavior.AllowGet);
}
I tried this and to
First, your li element isn't inside your app directive, which means it will not detect the function, you need to make sure that your li element is within the app scope
<!-- li is outside the scope -->
<li><a data-toggle="tab" href="#calificaciones" ng-click="ButtonCountry(1)"><span>Country</span></a></li>
<div ng-app="myApp" ng-controller="myCtrl">
<!-- end -->
<!-- li is within the scope -->
<div ng-app="myApp" ng-controller="myCtrl">
<ul>
<li><a data-toggle="tab" href="#calificaciones" ng-click="ButtonCountry(1)"><span>Country</span></a></li></ul>
<!-- end -->
of course, you need to alter your html elements, meaning ul parent of the li most be included as well.
your Action url is wrong, your controller shows that action name is CalificacionesAngular but you are using Angular for some reason, another thing I notice you never passed the code to your function which means
this
ng-click="ButtonCountry ()"
//should be this
ng-click="ButtonCountry('thecode')"
and the data you are posting isn't similar to the parameter name,
you have to change this
post("/Country/Angular", { CodH: Cod })
//to this
post("/Country/CalificacionesAngular", { codCountry: Cod })
there might be some more issues, these are the one I could see so far, please debug and provide more details about the error you are getting.
A good example you can check as well is this and this, and I suggest reading about Directives, Binding, scope, and Events
I have a view model in a ASP.Net application set up right now to handle some data binding and it interacts with a Razor template on my main view that is shared across several pages. I have a select box in the Razor template that has a data binding on my current view model, but I would have to duplicate this code across several view models to gain the same functionality and I want to just have this part of my view model be abstracted just like my template is an abstraction of the part of the view it is on. Ideally what I want is something like the following (psuedo-code):
class ViewModel1{
function doSomeAjaxStuff(option from select){
}
function doSomethingOnSelectorChange(option from select){
call doSomeAjaxStuff(option from select);
}
}
class SelectorViewModel{
function getSelectorValuesFromAjax(){
//this function will populate the selectors values from an ajax call
}
function sendMessageThatSelectorHasChanged(){
//this will send to the first viewmodel that the selector value has changed
}
}
I am a bit new to the MVVM architecture and I'm not exactly sure how to do this with knockout. Can someone help me out?
I'm not sure if this is what you're asking, but it sounds like you're looking to implement something like a reusable control using Knockout. One approach we're currently taking is using custom binding handlers in conjunction with template scripts. For example, given some templates:
<script type="text/html" id="selector-template">
<!-- ko if: isLoading -->
Loading data...
<!-- /ko -->
<!-- ko ifnot: isLoading -->
<ul data-bind="foreach: items">
<li data-bind="
css: { selected: $parent.selectedItem == $data },
template: $parent.itemTemplate,
click: selectItem">
</li>
</ul>
<!-- /ko -->
</script>
...and a binding handler:
ko.bindingHandlers.selector = {
init: function(element, valuesAccessor, allBindingsAccessor, viewModel, bindingContext) {
var bindingValues = valuesAccessor();
var templateElem = document.createElement('div');
templateElem.setAttribute('data-bind', 'template: "selector-template"');
element.appendChild(templateElem);
var viewModelForControl = new SelectorViewModel(bindingValues);
var childBindingContext = bindingContext.createChildContext(viewModelForControl);
ko.applyBindingsToDescendants(childBindingContext, element);
return { controlsDescendantBindings: true };
}
};
...you could instantiate the custom control like this:
<div data-bind="selector: {
itemsUrl: urlForItems,
selected: doSomethingOnSelectorChange,
itemTemplate: 'product-list-item-template'
}"></div>
<script type="text/html" id="product-list-item-template">
<img data-bind="attr: { src: imageUrl }" />
<span data-bind="text: description"></span>
</script>