How do I use ui.bootstrap in a MeanJS controller? - angularjs

Every time I try to use any of the bootstrap functions from ui.bootstrap, I get the following error:
Error: [$injector:unpr] Unknown provider: ui.bootstrapProvider <- ui.bootstrap <- CollapseController...
I've tried many various ways to fix this problem but I'm stuck at this point. Right now I'm just trying to make a toggle switch on a comments view. Here's my controller:
angular.module('remarks').controller('CollapseController', ['$scope', 'ui.bootstrap', 'ngAnimate',
function ($scope) {
$scope.isCollapsed = false;
}
]);
That's an additional controller to the default one (RemarksController) and I've registered the remarks module as such:
ApplicationConfiguration.registerModule('remarks', ['ngAnimate', 'ui.bootstrap']);
Finally, here's the view that is trying to make use of this controller:
<section ng-controller="RemarksController" ng-init="find()">
<div><h6>Remarks</h6></div>
<div class="container">
<div class="post-remarks">
<div class="row">
<div class="media" ng-controller="CollapseController">
<div class="media-heading">
<button class="btn btn-default btn-xs" type="button" ng-click="isCollapsed = !isCollapsed">
<span class="glyphicon glyphicon-minus" ng-if="(!isCollapsed)"></span>
<span class="glyphicon glyphicon-plus" ng-if="isCollapsed"></span>
</button>
</div>
<div class="panel-collapse collapse in" uib-collapse="isCollapsed">
(content)
</div>
Please understand, I can figure out ways around this to do this one operation differently. But, I don't want to. I want to be able to use the ui-bootstrap functionality so I'm trying to get to the root of the problem here.
How can I get the ui.bootstrap dependency to inject so I can use it in this controller?
Thanks

ui.bootstrap is by default added by MEAN 4.X. No need to register it in the controller.
https://github.com/meanjs/mean/blob/master/modules/core/client/app/config.js
I don't see the problem with your code..
http://jsfiddle.net/zdyv90w1/1/
var app = angular.module('app', []);
app.controller('CollapseController', function($scope) {
$scope.isCollapse = false;
});

Related

AngularJs UI Modal without $scope and extra ModalController (resolve)

I want to implement UI Modal in AngularJS without using $Scope and without implementing the ModalController(resolve).
I am not using $scope in my Controller. I am using vm = this. So I dont know what value to assign to scope while openinig the Modal.
I also dont want to use resolve, as it involves creating one more Controller.
Please find my code below: Any help will be greatly appreciated.
HTML
<script type="text/ng-template" id="modaltemplate.html">
<div class="modal-header">
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<p>Modal Body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="vm.close()" data-dismiss="modal">Close
</button>
</div>
</script>
CONTROLLER Look at scope in $uibModal.open() function.
angular
.module("app", ["ui.bootstrap"])
.controller("MyController", MyController)
MyController.$inject = ["$uibModal"];
function MyController($uibModal) {
var vm = this;
vm.open = open;
vm.close = close;
function open() {
vm.modalInstance = $uibModal.open({
templateUrl: 'modaltemplate.html',
scope: //what should I assign here, I dont want to use $scope. Or in other words, I want to assign 'vm' here.
});
}
function close() {
//This function is not getting called as it does not understand the vm.
}
}
I have tried the following things:
In the HTML, set ng-controller="MyController as vm".
Also tried setting various Values for scope, controller, and controllerAs in the $uibModal.open() function.
But nothing seems to working. Can anybody please help me out.
if you have problem with Close function, you can set $dismiss() for close modal instance, also you can pass parameter in $dismiss function for further use, try this:
<script type="text/ng-template" id="modaltemplate.html">
<div class="modal-header">
<h3>Modal Header</h3>
</div>
<div class="modal-body">
<p>Modal Body</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="$dismiss('cancel')" data-dismiss="modal">Close
</button>
</div>
</script>
You can create a new scope in main controller
var modalScope = $scope.$new();
assign what you need on new scope (or whole vm):
modalScope.vm = vm;
and then assign it as modal scope:
vm.modalInstance = $uibModal.open({
templateUrl: 'modaltemplate.html',
scope: modalScope
});
Just make sure you clear it when closing/destroying modal
modalScope.vm = null;

AngularJS add/removeClass does nothing?

I am trying to add and remove a class on button click. Unfortunately nothing I do seems to achieve this. The class never changes no matter what I do.
Here is what I am trying to change;
<div ng-controller="navbarCollaspeCtrl">
<nav id="mainNav" class="navbar fixed-top navbar-expand-lg navbar-transparent">
<button class="navbar-dark navbar-toggler" ng-click="changeClass()" href="" type="button" data-toggle="collapse" data-target="#navToggle" aria-controls="navToggle" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
And here is the Angular part;
.controller('navbarCollaspeCtrl', ['$scope', '$element', function($scope, $element) {
$scope.changeClass = function() {
var el = document.getElementById('mainNav');
$element.removeClass(el, "navbar-transparent");
$element.addClass(el, "navbar-primary");
console.log(el);
}
}])
The 'navbar-transparent does not get removed. And navbar-primary never gets added. Any thoughts?
There is no need to manipulate DOM elements like this for simple scenarios like this one (this is more of a jQueryish approach). Instead create a variable and bind to it to toggle the style.
Html
<nav id="mainNav" class="navbar fixed-top navbar-expand-lg" {{transparent ? 'navbar-transparent': ''}}">
JS
var myApp = angular.module('myApp',[]);
myApp.controller('navbarCollaspeCtrl', ['$scope', '$element', function($scope, $element) {
$scope.transparent = false;
}]);
You can also use ng-class directive.

AngularJs service not injected in controller

I am having trouble with something very simple like inject a basic service into a controller and despite reading documentation and other SO question i really don't see the mistake i'm making.
Here's my simplified code:
angular.module ('travelApp', ['ui.bootstrap', 'ngRoute'])
//CONTROLLERS
.controller('searchController', ['$scope','myParams', function ($scope,ngRoute,myParams){
$scope.place = myParams.place;
$scope.$watch('place', function(){
myParams.place = $scope.place;
});
$scope.bind = function(){
console.log(myParams.getPlace);
};
}])
//SERVICES
.service('myParams', function(){
this.place = 'start';
});
//MY HTML
<div class="container" ng-app="travelApp">
<div class="jumbotron" id="searchPage" ng-controller="place">
<div>
<h3>Start Here</h3>
<input type="text" class="form-control" id="searchBar" ng-model="place">
<a type="button" class="btn btn-default" ng-click="bind()">bind data</a>
</div>
</div>
I have tried a number of things in the past few hours but keep getting the
"TypeError: Cannot set property 'place' of undefined"
It seems the service is just no available inside the controller, i don't know if it has something to do with routing but i doubt so.
Can someone please point me in the right direction?
Here is a Plunker
Your dependencies must match if you use array syntax. Remove ngRoute from the controller's arguments.
.controller('searchController', ['$scope','myParams', function ($scope, myParams){

Dynamically parsing HTML with AngularJS

I'm new to Angular and I have hit a small problem. I would like to set different menus depending on the user being authenticated or not. Depending on the status laravel returns different menu structures (html).
Here's my HTML for the main menu:
<div class="navbar navbar-default navbar-fixed-top" role="navigation" ng-controller="MenuCtrl">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<img src="/image">
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li ng-bind-html="firstoption" ng-class="{active:isActive('/firstoption')}">{{ firstoption }}</li>
<li ng-bind-html="secondoption" ng-class="{active:isActive('/secondoption')}" class="dropdown">
{{ secondoption }}
</li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
Heres my Controller:
The backend returns a json with the html. The reason why I want to do it like that has also to do with user rights. Depending on different rights, different options are shown in the menu.
AppControllers.controller('MenuCtrl', ['$scope', '$http', '$sce', '$location',
function ($scope, $http, $sce, $location) {
$scope.isActive = function(route) {
return route === $location.path();
}
$scope.firstoption = "";
$scope.secondoption = "";
var getMenuStructure = $http.get('/menustructure').success(function (data) {
$scope.firstoption = $sce.trustAsHtml(data.firstoption);
$scope.secondoption = $sce.trustAsHtml(data.secondoption);
});
}]);
It seems to work nearly perfectly, but the console still gives me an error:
TypeError: Object [object Object] has no method 'indexOf'
Is there a more elegant way of doing it? What am I doing wrong?
UPDATE
The problem seems to be the $sce.trustAsHtml();. When I remove it, the dropdowns don't work anymore and when I add them I get the error.
The ng-include allows you to include data from an external URL and compile it on the fly.
This will allow you to write code like this:
<ng-include src="/views/{{viewname}}.html"></ng-include>
and then in your controller, simply set (or change) the view by setting $scope.viewname, like so:
$scope.viewname = "view"
Even if you don't need to dynamically change which page is loaded, it's worth using the ng-include for simplicities sake.
I ran into this same problem. I found that $sce.getTrusted worked the same as trustAsHtml for my case. It looks like this: $sce.getTrusted($sce.HTML, someHtml)

Invoking modal window in AngularJS Bootstrap UI using JavaScript

Using the example mentioned here, how can I invoke the modal window using JavaScript instead of clicking a button?
I am new to AngularJS and tried searching the documentation here and here without luck.
Thanks
OK, so first of all the http://angular-ui.github.io/bootstrap/ has a <modal> directive and the $dialog service and both of those can be used to open modal windows.
The difference is that with the <modal> directive content of a modal is embedded in a hosting template (one that triggers modal window opening). The $dialog service is far more flexible and allow you to load modal's content from a separate file as well as trigger modal windows from any place in AngularJS code (this being a controller, a service or another directive).
Not sure what you mean exactly by "using JavaScript code" but assuming that you mean any place in AngularJS code the $dialog service is probably a way to go.
It is very easy to use and in its simplest form you could just write:
$dialog.dialog({}).open('modalContent.html');
To illustrate that it can be really triggered by any JavaScript code here is a version that triggers modal with a timer, 3 seconds after a controller was instantiated:
function DialogDemoCtrl($scope, $timeout, $dialog){
$timeout(function(){
$dialog.dialog({}).open('modalContent.html');
}, 3000);
}
This can be seen in action in this plunk: http://plnkr.co/edit/u9HHaRlHnko492WDtmRU?p=preview
Finally, here is the full reference documentation to the $dialog service described here:
https://github.com/angular-ui/bootstrap/blob/master/src/dialog/README.md
To make angular ui $modal work with bootstrap 3 you need to overwrite the styles
.modal {
display: block;
}
.modal-body:before,
.modal-body:after {
display: table;
content: " ";
}
.modal-header:before,
.modal-header:after {
display: table;
content: " ";
}
(The last ones are necessary if you use custom directives) and encapsulate the html with
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
Open modal windows with passing data to dialog
In case if someone interests to pass data to dialog:
app.controller('ModalCtrl', function($scope, $modal) {
$scope.name = 'theNameHasBeenPassed';
$scope.showModal = function() {
$scope.opts = {
backdrop: true,
backdropClick: true,
dialogFade: false,
keyboard: true,
templateUrl : 'modalContent.html',
controller : ModalInstanceCtrl,
resolve: {} // empty storage
};
$scope.opts.resolve.item = function() {
return angular.copy(
{name: $scope.name}
); // pass name to resolve storage
}
var modalInstance = $modal.open($scope.opts);
modalInstance.result.then(function(){
//on ok button press
},function(){
//on cancel button press
console.log("Modal Closed");
});
};
})
var ModalInstanceCtrl = function($scope, $modalInstance, $modal, item) {
$scope.item = item;
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}
Demo Plunker
The AngularJS Bootstrap website hasn't been updated with the latest documentation. About 3 months ago pkozlowski-opensource authored a change to separate out $modal from $dialog commit is below:
https://github.com/angular-ui/bootstrap/commit/d7a48523e437b0a94615350a59be1588dbdd86bd
In that commit he added new documentation for $modal, which can be found below:
https://github.com/angular-ui/bootstrap/blob/d7a48523e437b0a94615350a59be1588dbdd86bd/src/modal/docs/readme.md.
Hope this helps!
Quick and Dirty Way!
It's not a good way, but for me it seems the most simplest.
Add an anchor tag which contains the modal data-target and data-toggle, have an id associated with it. (Can be added mostly anywhere in the html view)
Now,
Inside the angular controller, from where you want to trigger the modal just use
angular.element('#myModalShower').trigger('click');
This will mimic a click to the button based on the angular code and the modal will appear.
Different version similar to the one offered by Maxim Shoustin
I liked the answer but the part that bothered me was the use of <script id="..."> as a container for the modal's template.
I wanted to place the modal's template in a hidden <div> and bind the inner html with a scope variable called modal_html_template
mainly because i think it more correct (and more comfortable to process in WebStorm/PyCharm) to place the template's html inside a <div> instead of <script id="...">
this variable will be used when calling $modal({... 'template': $scope.modal_html_template, ...})
in order to bind the inner html, i created inner-html-bind which is a simple directive
check out the example plunker
<div ng-controller="ModalDemoCtrl">
<div inner-html-bind inner-html="modal_html_template" class="hidden">
<div class="modal-header">
<h3>I'm 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>
</div>
<button class="btn" ng-click="open()">Open me!</button>
<div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
inner-html-bind directive:
app.directive('innerHtmlBind', function() {
return {
restrict: 'A',
scope: {
inner_html: '=innerHtml'
},
link: function(scope, element, attrs) {
scope.inner_html = element.html();
}
}
});

Resources