Angular - Can I use $mdDialog in Http Interceptor Service? - angularjs

I'm using http interceptor to handle errors. Is it possible to use md-dialog to pop up a window showing error messages once some certain errors are captured. A circular dependency error occurs when injecting $mdDialog into the service. Where should I bind errorMsg if $mdDialog can be used in this service?
interceptor:
.factory('httpInterceptor', ['$q', '$mdDialog', function($q, $mdDialog){
return {
'response': function(res) {
var status = res.data.status;
var errorMsg = res.data.payload.message;
if(status === 'fail') {
$mdDialog.show({
// controller: ???,
// scope: ???,
templateUrl: 'error.html',
})
return $q.reject(res);
}
return res;
}
}
}])

Yes you can display the $scope variable using a controller and resolve,
$mdDialog.show({
controller: function($scope, $mdDialog){
// do something with dialog scope
},
template: '<md-dialog aria-label="My Dialog">'+
'<md-dialog-content class="sticky-container">{{test}}' +
'</md-dialog-content>' +
'<md-button ng-click=close()>Close</md-button>' +
'</md-dialog>',
controller: 'modalCtrl',
resolve: {
test: function () {
return 'test variable';
}
}
});
Controller:
app.controller('modalCtrl', function($scope, $mdDialog, test) {
$scope.test = test;
});
DEMO

Related

Angular modal service doesn't recognize the templateUrl

https://github.com/dwmkerr/angular-modal-service
When I want to show the modal, the console show this error
GET http://localhost:3000/copy/duplicate_view.html 404 (Not Found)
on the controller:
(function() {
'use strict';
function editCtrl($scope, appSettings,pricingService, ModalService) {
$scope.show = function() {
ModalService.showModal({
templateUrl: '../copy/duplicate_view.html',
controller: "DialogDemoCtrl"
})
};
}
angular.module('myApp')
.controller('editCtrl', editCtrl)
;
})();
On the HTML:
<a class="btn-green-alt btn" href ng-click="show()">{{'dialog.EXPORT' | translate}}</a>
at Dependency
angular
.module('myApp', [
'daterangepicker',
'angular-loading-bar',
'ui.tinymce',
'angularModalService'
])
And this is what i see on the service's code...
var getTemplate = function getTemplate(template, templateUrl) {
var deferred = $q.defer();
if (template) {
deferred.resolve(template);
} else if (templateUrl) {
$templateRequest(templateUrl, true).then(function (template) {
deferred.resolve(template);
}, function (error) {
deferred.reject(error);
});
} else {
deferred.reject("No template or templateUrl has been specified.");
}
return deferred.promise;
};
Set absolute path to your template whitout using ..
EDIT
Based on your comment about the project structure
app
specifications
copy
duplicate_view.html
Then set templateUrl as follow
templateUrl: 'app/specifications/copy/duplicate_view.html',

AngularJS: $modal, passing $scope variable to child controller

JS Code,
var mod= $modal.open({
animation: true,
templateUrl: $scope.url,
controller: function($scope, $modalInstance,custObj) {
alert(custObj); /*************Line 1**************************/
$scope.save = function() {
$modalInstance.close();
};
$scope.cancel = function(){
$modalInstance.dismiss('cancel');
};
},
resolve : {
/************Resolving current scope value to retrieve it in Line 1*******/
custObj: $scope.customer;
}
});
Though I sent $scope.customer object via resolve property, the modal controller is not getting the value. Am I missing anything?
The value of custObj in the resolve-object should be a function returning what you want to inject:
resolve: {
custObj: function(){
return $scope.customer;
}
}
check documentation for $routeProvider resolve
use
locals : {
custObj: $scope.customer;
}
instead of resolve.

AngularJS: passing data through modular window

I am trying to show flash message when deleting record. I can not achieve notice to show up, although I get proper true response if I use console.log after getting response from server.
View:
<p ng-show="offerDeletedSuccess" class="someClass">
Some notice
</p>
General controller:
$scope.offerDeletedSuccess = false;
$scope.open = function(offer) {
var modalInstance = $modal.open({
animation: true,
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
resolve: {
offerDeletedSuccess: function() {
return $scope.offerDeletedSuccess;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
});
};
Modal Instance controller:
angular
.module('someModule')
.controller('ModalInstanceCtrl', function ($http, $scope, $modalInstance, offerDeletedSuccess) {
$scope.ok = function() {
console.log(offerDeletedSuccess); // this returns false
$http.post('/api/offers/delete/' + offer.id).
success(function(data) {
offerDeletedSuccess = true;
console.log(offerDeletedSuccess); // this returns true, expression in html stays false
}).
error(function() {
console.log('API error - config.')
});
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
A quick solution for this is using $broadcast. You have to inject $rootScope into ModalInstanceCtrl. When the data is ready, ModalInstanceCtrl will broadcast an event called dataGet:
controller('ModalInstanceCtrl', function ($http, $scope, $modalInstance, $rootScope, offerDeletedSuccess) {
$http.post('/api/offers/delete/' + offer.id).
success(function(data) {
offerDeletedSuccess = true;
$rootScope.$broadcast('dataGet', offerDeletedSuccess);
}).
}
We can handle that event in general controller:
$scope.$on('dataGet', function(value){
//The value here is offerDeletedSuccess in ModalInstanceCtrl
$scope.offerDeletedSuccess = value;
});

How to handle error in angular-ui-router's resolve

I am using angular-ui-router's resolve to get data from server before moving to a state. Sometimes the request to the server fails and I need to inform the user about the failure. If I call the server from the controller, I can put then and call my notification service in it in case the call fails. I put the call to the server in resolve because I want descendant states to wait for the result from the server before they start.
Where can I catch the error in case the call to the server fails? (I have read the documentation but still unsure how. Also, I'm looking for a reason to try out this new snippet tool :).
"use strict";
angular.module('MyApp', ["ui.router"]).config([
"$stateProvider",
"$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/item");
$stateProvider
.state("list", {
url: "/item",
template: '<div>{{listvm}}</div>' +
'<a ui-sref="list.detail({id:8})">go to child state and trigger resolve</a>' +
'<ui-view />',
controller: ["$scope", "$state", function($scope, $state){
$scope.listvm = { state: $state.current.name };
}]
})
.state("list.detail", {
url: "/{id}",
template: '<div>{{detailvm}}</div>',
resolve: {
data: ["$q", "$timeout", function ($q, $timeout) {
var deferred = $q.defer();
$timeout(function () {
//deferred.resolve("successful");
deferred.reject("fail"); // resolve fails here
}, 2000);
return deferred.promise;
}]
},
controller: ["$scope", "data", "$state", function ($scope, data, $state) {
$scope.detailvm = {
state: $state.current.name,
data: data
};
}]
});
}
]);
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<div ng-app="MyApp">
<ui-view />
</div>
Old question but I had the same problem and stumbled on this in ui-router's FAQ section
If you are having issues where a trivial error wasn't being caught
because it was happening within the resolve function of a state, this
is actually the intended behavior of promises per the spec.
errors within resolve.
So you can catch all resolve errors in the run phase of your app like this
$rootScope.$on('$stateChangeError',
function(event, toState, toParams, fromState, fromParams, error){
// this is required if you want to prevent the $UrlRouter reverting the URL to the previous valid location
event.preventDefault();
...
})
The issue is that if any of the dependencies in the route resolve is rejected, the controller will not be instantiated. So you could convert the failure to data that you can detect in the instantiated controller.
Example Pseudocode:-
data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
return $timeout(function () { //timeout already returns a promise
//return "Yes";
//return success of failure
return success ? {status:true, data:data} : {status:false}; //return a status from here
}, 2000);
}]
and in your controller:-
controller: ["$scope", "data", "$state", function ($scope, data, $state) {
//If it has failed
if(!data.status){
$scope.error = "Some error";
return;
}
$scope.detailvm = {
state: $state.current.name,
data: data
};
If you are making an $http call or similar you can make use of http promise to resolve the data always even in case of failure and return a status to the controller.
Example:-
resolve: {
data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
return $http.get("someurl")
.then(function(){ return {status:true , data: "Yes"} },
function(){ return {status:false} }); //In case of failure catch it and return a valid data inorder for the controller to get instantated
}]
},
"use strict";
angular.module('MyApp', ["ui.router"]).config([
"$stateProvider",
"$urlRouterProvider",
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/item");
$stateProvider
.state("list", {
url: "/item",
template: '<div>{{error}}</div><div>{{listvm}}</div>' +
'<a ui-sref="list.detail({id:8})">go to child state and trigger resolve</a>' +
'<ui-view />',
controller: ["$scope", "$state", function($scope, $state){
$scope.listvm = { state: $state.current.name };
}]
})
.state("list.detail", {
url: "/{id}",
template: '<div>{{detailvm}}</div>',
resolve: {
data: ["$q", "$timeout","$http", function ($q, $timeout, $http) {
return $http.get("/").then(function(){ return {status:true , data: "Yes"} }, function(){ return {status:false} })
}]
},
controller: ["$scope", "data", "$state", function ($scope, data, $state) {
$scope.detailvm = {
state: $state.current.name,
data: data.status ? data :"OOPS Error"
};
}]
});
}
]);
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script data-require="angular-ui-router#*" data-semver="0.2.10" src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<div ng-app="MyApp">
<ui-view></ui-view>
</div>

Load controller dynamically based on route group

Is it possible to load a controller, it's js file, and a template dynamically based on a route group? Psuedo code which doesn't work:
$routeProvider.when('/:plugin', function(plugin) {
templateUrl: 'plugins/' + plugin + '/index.html',
controller: plugin + 'Ctrl',
resolve: { /* Load the JS file, from 'plugins/' + plugin + '/controller.js' */ }
});
I've seen a lot of questions like this one but none that loads the js file/controller based on a route group.
I managed to solve it inspired by #calebboyd, http://ify.io/lazy-loading-in-angularjs/ and http://weblogs.asp.net/dwahlin/archive/2013/05/22/dynamically-loading-controllers-and-views-with-angularjs-and-requirejs.aspx
Using http://dustindiaz.com/scriptjs
app.js
app.config(function($controllerProvider, $compileProvider, $filterProvider, $provide) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
});
Then i register the "load controller by group" route.
$routeProvider.when('/:plugin', {
templateUrl: function(rd) {
return 'plugin/' + rd.plugin + '/index.html';
},
resolve: {
load: function($q, $route, $rootScope) {
var deferred = $q.defer();
var dependencies = [
'plugin/' + $route.current.params.plugin + '/controller.js'
];
$script(dependencies, function () {
$rootScope.$apply(function() {
deferred.resolve();
});
});
return deferred.promise;
}
}
});
controller.js
app.register.controller('MyPluginCtrl', function ($scope) {
...
});
index.html
<div ng-controller="MyPluginCtrl">
...
</div>
You can use RequireJS to do this. Something like:
$routeProvider.when('/:plugin',{
templateUrl: 'plugins/' + plugin + '/index.html',
controller: plugin + 'Ctrl',
resolve: {myCtrl: function($q){
var deferred = $q.defer();
require('myCtrlFile',function(){
deferred.resolve();
});
return deferred.promise;
}}
});
You will also need to register the controller dynamically. By exposing your providers in the app config.
app.config(function($controllerProvider,$compileProvider,$filterProvider,$provide){
app.register =
{
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
});
You controller file might then look like:
define(['app'],function(app){
app.register.controller('myCtrl',MyCtrlFunction);
});
This is just the general idea. I use a similar implementation to the one described here
I also use ui-router. I'm not certain if behavior is the same with ngRoute.
Here is some solution you can do for this code
$routeProvider.when('/:plugin', function(plugin) {
templateUrl: 'plugins/' + plugin + '/index.html',
controller: fun,
loadFrom:"assets/controller/myJsController"// this is our custom parameter we are passing to controller to identify the remote controller file.
});
We will create a parent function for all controller and will call all controller within this function as per defined in route configuration (in loadFrom key of route configuration).
function fun($scope, $http, $location, $timeout, $route) {
$timeout(function () {
var path = $route.current.loadForm;
$http.get("${pageContext.servletContext.contextPath}/resource/controller/" + path + ".js")
.then(function (rsp) {
eval(rsp.data);
});
});
};
in assets/controller/myJsController.js file the code will be as
(function($scope){
//the whole code for controller will be here.
$scope.message="working."
})($scope)
Only thing you have to remember that in parent function you have to use all dependencies.
Simplest way with active this with less amount of code
require.js config file.
require.config({
urlArgs: 'v=1.0',
baseUrl: '/'
});
app.config(['$controllerProvider', '$compileProvider', '$filterProvider', '$provide','$routeProvider',function($controllerProvider, $compileProvider, $filterProvider, $provide,$routeProvider) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
// Resolver to load controller, service, directive
var resolveController = function(dependencies) {
return {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var defer = $q.defer();
require(dependencies, function () {
defer.resolve();
$rootScope.$apply();
});
return defer.promise;
}]
}
};
$routeProvider
.when("/home", {
templateUrl : "templates/home.html",
controller: 'HomeCtrl',
resolve: resolveController(['controller/HomeCtrl'])
})
.when("/ContactUs", {
templateUrl : "templates/ContactUs.html",
controller: 'ContactUsCtrl',
resolve: resolveController(['controller/ContactUsCtrl'])
})
.when("/About", {
templateUrl : "templates/About.html",
controller: 'AboutCtrl',
resolve: resolveController(['controller/AboutCtrl'])
});
$routeProvider.otherwise('/home');
}]);
Your controllers should look like this.
define(['app'],function(app){
app.register.controller('HomeCtrl',['$scope',function($scope){
// Controller code goes here
}]);
});

Resources