AngularJS & Bootstrap Modal - loading template outside controller - angularjs

I have a dialog which is being used in 3 scenarios within the same page. I have created a controller similar to the below:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">Im a modal!</h3>
</div>
<div class="modal-body">
<ul>
<li ng-repeat="item in items">
<a ng-click="selected.item = item">{{ item }}</a>
</li>
</ul>
Selected: <b>{{ selected.item }}</b>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">OK</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
</script>
The issue is, that since this dialog is being used in 3 different parts of the same page, I have a problem with the template. When I put the html template outside of the controller, at the very end of the page html, it fails and gives me a 404.
However, I do not wish to repeat the same chunk of HTML in 3 places in the same page. Can someone tell me if there's a different way of calling the template which is outside the controller?

A good way to reuse your template is to put it in a separate html file and put its url in templateUrl. So $modal can get it from server every time needed.

Related

Angularjs ng-show issue with ng-route

I'm newbie to angular world. I'm trying to create a login page.When the user login, i want to show some contents in the navbar.
Currently i'm using ng-show and ng-route. When i'm not using ng-route, ng-show works fine but when i use ng-route, ng-show is not working .I don't want to use angular-ui-router. What i'm doing wrong. Can anyone help me
Angular Config
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'login.html',
controller: 'ctrl'
})
.when('/logged', {
templateUrl: 'logged.html',
controller: 'ctrl'
})
otherwise({
redirectTo: '/'
});
}]);
app.controller("ctrl",['$scope','$http','$location',function($scope,$http,$location){
$scope.myvalue2=false;
$scope.login = function()
{
//here i making the $http.post to login on success im changing $scope.myvalue2=true;
}
}]);
HTML
<nav class="navbar-default navbar-dark bg-primary">
<div class="navbar">
<div class="container-fluid navi">
<div class="navbar-header" style="padding-bottom:10px">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<ul class="navbar-brand " style="list-style:none;padding-top:10px;"><li>name</li></ul>
</div>
<div ng-show="myvalue2" class="ng-cloak">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" style="padding-top:10px">
<ul class="nav navbar-nav">
<li>About</li>
<li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#" style="font-size:14px;">Settings</a></li>
</ul>
</div>
</div>
</div>
</div>
</nav>
I don't think that ngRoute would have any impact on ng-show. It's working fine check this working demo :
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.myvalue2 =false;
$scope.login = function() {
$scope.myvalue2=true;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<a ng-click="login()">Login</a>
<div ng-show="myvalue2">
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1" style="padding-top:10px">
<ul class="nav navbar-nav">
<li>About</li>
<li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#" style="font-size:14px;">Settings</a></li>
</ul>
</div>
</div>
</div>
You're going to want to use the digest cycle here, and do away with ng-show, since its use gets easily mistaken for the more elegant and simpler-to-understand ng-if.
In short:
AJAX calls will trigger a digest cycle.
ng-if will actively remove DOM if its condition is not met, thus drawing less DOM.
Changing the value on an AJAX call in an ng-if will work instead of hiding the DOM element, since it'll be eligible to be visible anyway.
The ng-cloak class is throwing me off; you probably don't need that there, since with ng-if, it won't be anywhere in the DOM until you actually need it.
What your controller might look like:
app.controller("ctrl", [
'$scope',
'$http',
'$location',
function ($scope, $http, $location) {
$scope.myvalue2 = false;
$scope.login = function () {
$http.get('/path/to/your/request', function(data) {
$scope.myvalue2 = true;
});
}
}]);
What your DOM would need to change to (and yes, I prefer absolute truth to truthiness):
<div ng-if="myvalue2 === true">
This will help you,
<div ng-app="myApp" ng-controller="myCtrl">
<button class="btn btn-success" type="text" ng-model="firstName" ng-show="display" ng-click="display=!display"> BUTTON 1</button>
<br />
<button class="btn btn-warning" ng-click="display=!display" ng-model="lastName" ng-show="!display"> BUTTON 2
</button>
</div>
DEMO

binding information in a HTML element

I have a http.get that returns an Array of Applications
<div id ="app" ng-repeat="app in applications" >
<carddata-toggle="modal" data-target="#myModal" ></card>
</div>
For each of them, i create a card (custom directive...think google now cards) and add a bootstrap modal to them. The idea being you can then click on each card and get more info about that specific app.
In the code for my Modal, I want to retrieve information about the app (for example the app name). As this is outside the for loop, Angular has lost track of my app name and therefore throws an error.
<div class="modal modal-fullscreen fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">{{app.name}} Status</h4>
</div>
I have read through the angular Api... I was looking for a way to "bind" the app name to the modal so it is aware of it, but couldn't see anything suitable. I'm new to Angular and I am therefore probably not approaching it right.
How would you approach this?
I would suggest to use Angular UI's modal service (have a look at https://angular-ui.github.io/bootstrap/#/modal).
In your controller (where you load your array of applications), inject $uibModal, e.g.
angular.module('myApp').controller('myCtrl', function ($scope, $uibModal) {
$scope.applications = [];
$scope.openModal = function(app) {
$uibModal.open({
controller: 'ModalInstanceCtrl',
templateUrl: 'myModalContent.html',
resolve: {
app: function() {
return app;
}
}
});
}
});
Then define the controller for the modal itself.
// This is the controller for the modal itself
// `app` being passed through the resolve parameter in $uibModal.open()
angular.module('myApp').controller('ModalInstanceCtrl', function ($scope, $uibModalInstance, app) {
$scope.app = app;
$scope.ok = function () {
$uibModalInstance.close();
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
You can define your modal template by putting the following in your view:
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">{{ app.title }}</h3>
</div>
<div class="modal-body" id="modal-body">
Modal body content
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" ng-click="ok()">OK</button>
<button class="btn btn-warning" type="button" ng-click="cancel()">Cancel</button>
</div>
</script>
I've avoided the controllerAs syntax as you did seem to use $scope in your example.
In your view
<div id ="app" ng-repeat="app in applications" >
<carddata-toggle="modal" data-target="#myModal" ng-click="setApp(app)"></card>
</div>
<h4 class="modal-title" id="myModalLabel">{{selectedApp.name}} Status</h4>
In your controller
$scope.setApp = function(appParam){
$scope.selectedApp = appParam;
}

Angular ui router - nested view inside modal

I want to put a Steps Wizard into a Modal.
Here is my working Wizard: plunker http://plnkr.co/edit/achnwMtmebR3oc8bq7pp?p=preview
Here is my working modal: http://plnkr.co/edit/ux1Ju6m2s9VqiIPjmH1n?p=preview
How do I add this working wizard to a modal? Can nested states be multiple states or limited to no more than two?
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show our basic form (/form)
.state('form', {
url: '/form',
templateUrl: 'form.html',
controller: 'formController'
})
// nested states
// each of these sections will have their own view
// url will be nested (/form/profile)
.state('form.profile', {
url: '/profile',
templateUrl: 'form-profile.html'
})
// url will be /form/interests
.state('form.interests', {
url: '/interests',
templateUrl: 'form-interests.html'
})
// url will be /form/payment
.state('form.payment', {
url: '/payment',
templateUrl: 'form-payment.html'
});
// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/form/profile');
})
just merge your HTML and JS files, move ui-view inside modal
HTML:
<body ng-app="formApp">
<div ng-controller="MainCtrl as mainCtrl">
<button type="button"
class="btn btn-default"
ng-click="mainCtrl.page.open()">Open Modal</button>
<!-- modal -->
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title" id="modal-title">I'm a modal!</h3>
</div>
<div class="modal-body" id="modal-body">
<!-- views will be injected here -->
<div class="container">
<div ui-view></div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-default pull-left"
type="button"
ng-click="modalInstanceCtrl.modal.cancel()">Cancel</button>
</div>
</script>
</div>
<div class="row">
<div class="col-sm-8 col-sm-offset-2">
<div class="jumbotron text-muted text-center">
<p>a tutorial by scotch.io</p>
<p>Create a Multi-Step Form Using Angular and UI-Router</p>
</div>
</div>
</div>
</body>
plunker: http://plnkr.co/edit/NaTveRiM5OTufouRo2v7?p=preview
it's better not to put routing inside your modal. You better write your own form steps. The logic is easy. You do not need separate routes. When the "next" button is pressed, you will increase the pageNumber. You can put different divs for each page. You can hide/show the pages using ng-show or ng-hide directives.

How to pass value to modal in Mobile Angular Ui modal?

I am using Mobile Angular UI.
In parent window there is list of category names. I want selected category name should get updated from modal. I am able to display modal. I want to pass selected category item from parent view to modal.
My code in parent view
<div ng-controller="CategoryController as TitleCats">
<div ng-repeat="cats in TitleCats.categories">
<a href=""
ui-turn-on="titleCatUpdatemodal"
class="btn btn-default" ng-click="TitleCats.openUpdateModel(cats)"> {{cats.name}} --> Edit</a>
</div>
<div ui-content-for="modals">
<div ng-include="'pages/titleCatUpdatemodal.html'"></div>
</div>
</div>
My Modal is
<div class="modal" ui-if='titleCatUpdatemodal' ui-state='titleCatUpdatemodal'>
<div class="modal-backdrop in"></div>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close"
ui-turn-off="titleCatUpdatemodal">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
<p><input type="text" ng-model="cats.name" >{{ cats.name }}</p>
</div>
<div class="modal-footer">
<button ui-turn-off="titleCatUpdatemodal" class="btn btn-default">Close</button>
<button ui-turn-off="titleCatUpdatemodal" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
When i click button it opens modal but no value!
Anyone please let me know how to get value in modal. Thanks in advance.
In your controller. you should have something similar to this:
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'templates/myModal.html',
controller: 'myModalCtrl',
resolve: {
myData: function () {
//do stuff
return stuff;
}
}
});
Inside that resolve, you can fill out the function which should then be accessible in your modals controller

angular js scope watch not updating bootstrap badge counter

I am an angular newbie. Fiddling around with $scope.
I have this snippet in my main view:
<div ng-controller="MainCtrl" class="ng-scope">
<ul class="nav navbar-nav navbar-right">
<li></span><span class="badge">{{ badgeCount }}</span></li>
</ul>
</div>
....
<div class="container">
<ui-view></ui-view>
</div>
home.html gets loaded through ui-view.
Inside home.html, I have
<div ng-repeat='item in items'>
<td> <button type="submit" class="btn btn-default btn-lg btn-success" ng-model="orderCnt" ng-click="placeOrder(item.desc)"><span class="glyphicon glyphicon-cutlery"></span></button> </td>
</div>
The controller is MainCtrl.
My controller is:
controller('MainCtrl', ['$scope', function($scope, menus) {
$scope.items = [];
$scope.badgeCount = 0;
$scope.orderCnt = 0;
console.log("badgecount=",$scope.badgeCount)
console.log("ordercnt=",$scope.orderCnt)
$scope.placeOrder = function(value) {
$scope.orderCnt ++;
console.log(value)
console.log($scope.orderCnt)
console.log("ng click")
};
$scope.$watch('orderCnt', function(newVal, oldVal){
console.log(newVal + " " + oldVal);
$scope.badgeCount++;
console.log("watch")
},true);
For any ng-click on placeOrder, I would expect the badgeCount to get updated on the shopping cart icon as well. Its not happening. Do I need to emit/broadcast this since its a different view? I was thinking since both have same controllers, same $scope would be bound. Any help would be appreciated.
Is your container div a child of the <div ng-controller="MainCtrl" class="ng-scope">? If not then they will have different scopes. Changes in one will not be seen in another.
Some other points
you don't need ng-model defined on the button, doesn't make sense cause it doesn't get changed.
why are you watching orderCnt in this case? It only changes in scope.placeOrder so you can call $scope.badgeCount++; in scope.placeOrder
EDIT: If you want the view to have the same scope you can place it as a child of the main controller. Also note that you're missing a > in your definition of <a href"#"
<body ng-controller="MainCtrl">
<ul class="nav navbar-nav navbar-right">
<li><span class="glyphicon glyphicon-shopping-cart gi-2x"></span><span class="badge">{{ badgeCount }}</span></li>
</ul>
<div class="container">
<ui-view></ui-view>
</div>
</body>

Resources