angularjs $compile is not working on production - asp.net-mvc

I am using angularJS in my MVC application and loading a partial using ajax call in angularJS. I am using $compile to compile the html. Everything is working fine on local but it is not working on production. Unexpected error is showing. Below is the code I am using.
Angular Controller:
app.controller("mproductController", ["$scope", "mproductService", "$compile", function ($scope, mproductService, $compile) {
$scope.ShowProdUnitPop = function (val) {
mproductService.ShowProdUnitPop(val).success(function (result) {
debugger;
var snippet = angular.element(result);
$compile(snippet)($scope);
$("#dvAddProd").html(snippet);
$("#dvPopup").modal('show');
});
}
}
Angular Service:
app.service("mproductService", ["$http", function ($http) {
this.ShowProdUnitPop = function () {
var request = $http({
method: "post",
url: "/Home/GetActiveCat"
});
return request;
}}
MVC Controller:
[HttpPost]
public ActionResult AddProduct(int id)
{
ViewBag.ProductCategory = Utility.GetProd(id);
return PartialView("_AddProduct",new Product());
}
Error is throwing on this line:
var snippet = angular.element(result);
$compile(snippet)($scope);
$("#dvAddProd").html(snippet);
$("#dvPopup").modal('show');
It is working on local but not on production. Please help.

Seems like you are using bundling and minification enabled on production server. That is breaking you controller code while you are utilizing that controller and its necessary to have inline array annotation of DI while minifying JS files.
Most possible answer would be you are using $compile by injecting it to controller and using it, That's fine. It seems like you had not followed inline array dependency injection inside your controller.
Also you need to attach compile element to your dvAddProd element, rather than updating html, appending html to DOM will never make angular angular binding on that element. Looks like this code shouldn't be working on any of the environment if it has angular bindings on it.
Controller
app.controller('someCtrl', ['$scope', '$http', '$compile',
function($scope, $http, $compile) {
//you should have controller in this way that would fix your issue
//note I'm using inline array notation of DI
$scope.ShowProdUnitPop = function(val) {
mproductService.ShowProdUnitPop(val).success(function(result) {
debugger;
var snippet = angular.element(result);
var compiledSnippet = $compile(snippet)($scope);
$("#dvAddProd").append(compiledSnippet); //should attach compile element
});
}
}
]);
Visit this link for more Information

Related

Calling controller method with a get type not working in ASP.NET MVC

I have a java script function that calling a controller method using Ajax, this call should get me the user profile page, I have a controller for this purpose. When I run the program and fire the java script function it's trigger the controller and every thing is good but when the debugging has ended no changes happens and the view doesn't present in the screen.
I tracked the call and every thing is working fine, passing parameter and reaching the method in the controller.
Note: the view which has the JS call related to a different controller.
View contain java script call:
<td onclick="ViewProfile('#item.CustomerId')"></td>
Java script file
function ViewProfile(id) {
console.log("sucsses");
$.ajax({
type:"GET",
url: "/ViewUserProfile/Index",
data: { "userId": id }
});
};
Controller: ViewUserProfileController
public ActionResult Index(string userId)
{
var ProfileInformation = new UserProfileVM
{
//some logic here
};
return View(ProfileInformation);
}
You are fetching ViewUserProfile in $.ajax but you are not using .done(function() { }) to process the result you receive from that call.
In your case I would simply suggest to use window.location.href in ViewUserProfile() as below.
function ViewProfile(id) {
window.location.href = "/ViewUserProfile/Index?userId=" + id;
}

405 method not allowed MVC 4 POST was working before

I have a really baffling issue with a customer site. We developed a C# MVC 4.0 application that's running in a subdirectory from another ASP.net application. We use a lot of Ajax calls from JQuery to controllers. Recently there's been an issue where a particular method on a controller has started returning "405 method not allowed" when doing a POST. This method is no different from any of the numerous other Ajax methods which are fine.
Edited to provide code:
Here's the offending function:
JavaScript:
function populateCitiesLike(cityTerm, fnInitialCityNames) {
var serviceBase = 'ProjectCities/';
var cityData = { term: cityTerm };
$.ajax({
type: "POST",
data: JSON.stringify(cityData),
url: serviceBase + "GetCitiesThatStartWith/",
contentType: "application/json",
success: function (result) {
$("#cityCheckboxes").empty();
if (result.length === 0) {
return;
}
addCityCheckboxes(result);
if (fnInitialCityNames != null)
fnInitialCityNames();
},
error: function () {
alert("We have an error");
}
});
}
c# controller :
[AjaxOnly,HttpPost]
public ActionResult GetCitiesThatStartWith(string term)
{
List<string> dbCities = null;
List<Cities> cityList = new List<Cities>();
dbCities = _reposProject.GetCitiesThatStartWith(term);
cityList = GetJsonFormatForCityList(dbCities);
// return Json(result);
return Json(cityList, JsonRequestBehavior.AllowGet);
}
I copied the entire web application and created a new subdirectory just to see what would happen. So for example the current application is running under main\A directory and now the cloned application is running under main\B. the method GetCitiesThatStartWith running under main\A that returns a 405 but the same method under main\B works. However there is one specific method called GetCitiesFromRegion that is always failing on both. That particular method used to work.
I don't think it's a code issue because why would one work and the other not. Resetting IIS does not work either. I can add test methods to the controller and call them from a test Ajax page and sometimes they fail and sometimes not. Once they fail with that particular method name I can no longer make it work. It's almost as if IIS remembers that the method failed and is caching the error.
updated
After spending more time with it I have discovered 2 issues. One issue is that the controllers constructor was throwing an exception because it was not authenticated at that point. I have resolved that issue.
The other issue which is baffling is that I could not get GetCitiesThatStartWith to work and a few other methods. I renamed them by appending V2 to the end of the method name and now they work.
Why would renaming a method on a controller make it work? I suspect that once the method gets an error and it stops working then I have to rename the method. Something about throwing an exception in the controller can be fatal to your method name apparently.
I think this will help you:-
I have changed the method name to CitiesThatStartWith by default it will be mapped with Get request because you are using GetCitiesThatStartWith.
Controller code
[AjaxOnly,HttpPost]
public ActionResult CitiesThatStartWith(string term)
{
List<string> dbCities = null;
List<Cities> cityList = new List<Cities>();
dbCities = _reposProject.GetCitiesThatStartWith(term);
cityList = GetJsonFormatForCityList(dbCities);
// return Json(result);
return Json(cityList, JsonRequestBehavior.AllowGet);
}
Javascript code
function populateCitiesLike(cityTerm, fnInitialCityNames) {
var serviceBase = 'ProjectCities/';
var cityData = { term: cityTerm };
$.ajax({
type: "POST",
data: JSON.stringify(cityData),
url: serviceBase + "CitiesThatStartWith/",
contentType: "application/json",
success: function (result) {
$("#cityCheckboxes").empty();
if (result.length === 0) {
return;
}
addCityCheckboxes(result);
if (fnInitialCityNames != null)
fnInitialCityNames();
},
error: function () {
alert("We have an error");
}
});
}

Callback after .swap() not working - ASP.NET SPA w/sammy.js

I am building a Single Page Application using ASP.NET and sammy.js, where all views except for the Home/Index view are rendered as partial views so that sammy can swap out the content of the main body with the partial view that is returned.
I am using the example given here, and everything loads fine as expected.
Similar to the above example, in my Home/Index page I have reference to a script called routing.js, which wraps the sammy function call in order to parse the MVC route:
var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = defaultRoute;
return url;
}
return {
init: function () {
Sammy(contentSelector, function () {
this.get(/\#\/(.*)/, function (context) {
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run('#/');
}
};
}
I need to call a callback function after the content swap has fully completed in order to implement further jQuery functionality on the newly rendered content. My dilemma is that no matter what option I try from the sammy.js docs, nothing seems to run the callback after the content has been swapped.
I have tried all of the following (all "valid" ways of passing a callback according to the sammy.js docs):
content.load(url).swap(pageLoadScripts(url));
content.load(url).swap().onComplete(pageLoadScripts(url));
content.load(url).swap().then(pageLoadScripts(url));
content.load(url).swap().next(pageLoadScripts(url));
content.load(url,pageLoadScripts(url)).swap();
and even
content.load(url).swap();
pageLoadScripts(url);
In every case the pageLoadScripts function fires off prior to the content being swapped. Any ideas or suggestions on what to do differently?
This is a bit of a hack, but it works.
Inside the Sammy initialization function, I added the following override to the swap function just before the override to the get function:
this.swap = function (content, callback) {
var context = this;
context.$element().html(content);
pageLoadScripts(hashedUrl);
};
FWIW, I still have not been able to get callback to be anything other than 'undefined', even in this override function.
Managed to get this working:
// override for callback after page load
this.swap = function(content, callback) {
this.$element().html(content);
if (callback) {
callback();
}
};
// users
this.get('/#/users', function(context) {
context.load('/users').swap(function() { replaceBindings(viewModel.users); });
});
I managed to get the callback param to NOT be 'undefined' by wrapping it in another function.

How to create a 'url_for' link helper in AngularjJS

In .NET MVC there is #Url.Action() and in RoR there is url_for()
I could not find similar url building helper in angularjs.
I'm already providing everything that is needed to build url to $routeProvider so something like: $routeProvider.urlFor("MyCtrl", {id: 5}) could be nice to have.
My main goal here is to avoid hardcoded urls in viewes and other places and to avoid repeating url/routes patterns twice.
UPDATE:
Seems like it's hard to explain what i want so here is exact example of what i want:
Instead of writing this in viewes:
<a ng-href="/product/5">foo</a>
I want to write this:
<a ng-href="urlFor("ProductCtrl", {id:5})">foo</a>
So if later i decide to change path of ProductCtrl I would not have to update url in this a element.
What would be good solution for my goals?
You could try with something like the following (just came up with it) inside your main module's run() block:
app.run(function($route, $rootScope)
{
$rootScope.path = function(controller, params)
{
// Iterate over all available routes
for(var path in $route.routes)
{
var pathController = $route.routes[path].controller;
if(pathController == controller) // Route found
{
var result = path;
// Construct the path with given parameters in it
for(var param in params)
{
result = result.replace(':' + param, params[param]);
}
return result;
}
}
// No such controller in route definitions
return undefined;
};
});
This will extend the root scope of the application with the new path() function - so it can be used anywhere in the application. It uses the $route service to get the controller names and the corresponding paths, so you won't have to repeat yourself.
Example usage:
{{ path('LibraryController', { bookId : 'x', chapterId : 'y' }) }}
Live example at: http://plnkr.co/edit/54DfhPK2ZDr9keCZFPhk?p=preview
There are numerous approaches...a custom directive or ng-click to modify $location, or using a function in ng-href to parse the url from object and have it placed as href in an <a> tag.
Example using ng-href:
HTML:
<li ng-repeat="item in items">
<a ng-href="{{url(item)}}">{{item.txt}}</a>
</li>
JS:
function Ctrl($scope){
$scope.items=[
{id:1,txt:'foo'},
{id:2,txt:'bar'}
];
$scope.url=function(item){
return '#/'+item.id
}
}
Example using ng-click and $location
HTML:
<a ng-click="newPath(item)">{{item.txt}}</a>
JS:
function Ctrl($scope){
$scope.items=[
{id:1,txt:'foo'},
{id:2,txt:'bar'}
];
$scope.newPath=function(item){
$location.path('/'+item.id)
}
}
DEMO: http://jsbin.com/ovemaq/3
In one of recent project I came up to this solution it helped me to solve my needs right in time. It will be interesting to help you to improve it to fit your usecase.
1. Move routes definition to config:
...
ROUTES: {
PAGE1: '/page1/:id',
PAGE2: '/page2/:id/:name'
},
...
2. Define routes, using values from config:
app.config(['$routeProvider', 'config', function ($routeProvider, config) {
$routeProvider.when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$routeProvider.when(config.ROUTES.PAGE1, {
templateUrl: 'partials/page1.html',
controller: 'PageOneCtrl'
});
...
$routeProvider.otherwise({
redirectTo: '/'
});
}]);
3. Set up service to provide functionality to create urls:
services.factory('routes', function (config) {
// populates `:param` placeholder in string with hash value
var parseString = function (string, parameters) {
if (!string) return '';
if (!parameters) return string;
for (var index in parameters) {
if (!parameters.hasOwnProperty(index)) continue;
string = string.replace(':' + index, parameters[index]);
}
return string;
};
return {
getPage1Link: function (urlParams) {
return '#' + parseString(config.ROUTES.PAGE1, urlParams);
}
};
});
== Drawbacks ==
With this approach I had to define getter for each route (there were less then 5, and development speed was vital)
It appears that what you want is the ui-route directive which has just been recently added to the angularui project. There is a nice set of out-of-the-box options.

Dotnetnuke partial rendering make my jQueryUI widget stop working

I want to use tab widget of jQueryUI in dotnetnuke 5.6.3
I registered jQueryUI in my module and it works fine but when I use partial Rendering in my page it fails to load.
Here is my code:
$(document).ready(function () {
rastaAdmin();
});
function rastaAdmin() {
var tabdiv = $('#tabul');
var tabvar = tabdiv.tabs();
}
this site have a method to solve my problem but it doesn't work in my script.
After reading the above site I changed my code to:
$(document).ready(function () {
rastaAdmin();
});
function pageLoad(sender, args) {
rastaAdmin();
}
function rastaAdmin() {
var tabdiv = $('#tabul');
var tabvar = tabdiv.tabs();
}
This Doesn't work for me.
What Can I do?
Thank You
I've had issues using the pageLoad function as well (though I don't remember now where it ended up breaking down). However, something like the other method should work fine (see the new jQuery UI setup in the core modules in DNN 6):
$(document).ready(function () {
setupDnnSiteSettings();
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function () {
setupDnnSiteSettings();
});
});
The one caveat here is that this registers the setup code to happen after returning from any UpdatePanel-initiated request, not just your specific UpdatePanel. Calling tabs again on the same element shouldn't cause any issue, but you'll want to figure out a way to differentiate if you're doing something that should only be called once.
Thank you bdukes
After your help, I changed my code to:
$(document).ready(function () {
Sys.Application.add_load(function (s, e) { rastaAdmin(); });
rastaAdmin();
});
function rastaAdmin() {
var tabdiv = $('#tabul');
var tabvar = tabdiv.tabs();
}
And It Works Like a charm for me! Thank You mate.

Resources