AngularJS add/removeClass does nothing? - angularjs

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.

Related

Ng-Click not firing Button is Clicked

So have a modal with a two buttons on it. One to close the modal, and one that should fire a function when clicked. I've attached a controller to the modal, and the controller itself works, as it does a successful console.log(). The ng-click doesn't seem to fire the function though. I think I just need another set of eyes on this, and it is greatly appreciated.
HTML:
<div id="forwardCall" class="modal fade" ng-controller="CallCtrl as call">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4>Transfer Call</h4>
</div>
<!-- dialog body -->
<div class="modal-body">
<p>Select Person below</p>
<div id="transferSelection">
<?php echo $transferCallSelect; ?>
</div>
</div>
<!-- dialog buttons -->
<div class="modal-footer">
<button class="btn btn-warning" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="call.hideControls()">Transfer Call</button></div>
</div>
</div>
</div>
Controller:
app.controller('CallCtrl', ['$scope', '$http', function($scope, $http){
console.log("Call Controller");
function hideControls(){
console.log("Controls Hidden");
var well = document.getElementById('callControls');
well.style.display = 'none';
}
}]);
If you are using controller as syntax, you are binding to this variable instead of $scope. Here is a good post talked about Controller As Syntax.
tymejv gave you a good suggestion. You have to binding the function to this when you are using controller as syntax. So that you can access the function or variable for this particular controller.
this.hideControls = function() { ... };
You can binding to function to the $scope as well:
$scope.hideControls = function() { ... };
controller.js
(function () {
'use strict';
angular
.module('app')
.controller('CallCtrl', CallCtrl);
CallCtrl.$inject = ['$scope', '$http'];
function CallCtrl($scope, $http) {
var vm = this;
console.log("Call Controller");
vm.well = true;
vm.hideControls = function () {
console.log("Controls Hidden");
//Do not to this! This is not jQuery
//var well = document.getElementById('callControls');
//well.style.display = 'none';
vm.well = false;
};
}
}());
index.html
<div id="forwardCall" class="modal fade" ng-controller="CallCtrl as call">
<div ng-show={{ call.well }}>Some content</div>
</div>

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

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;
});

Angular-Fullstack + UI router isn't routing properly

I'm attempting to route my application using UIrouter with the current yeoman-fullstack generator without mongoDB. In this example of my issue, everything is default to test and make sure the UI-router is working properly.
Mainly because I'm not understanding and missing something silly and noobish here, so I apologize.
https://github.com/DaftMonk/generator-angular-fullstack
I'm attempting to edit my routes in client/app/app.js using
'use strict';
angular.module('sr388App', [
'ngCookies',
'ngResource',
'ngSanitize',
'ui.router',
'ui.bootstrap'
])
.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider
.otherwise('/');
$stateProvider
.state('about', {
url: '/about',
template: '<h1>Attempting to have this point at /main/about.html but this is for testing purposes</h1>'
});
$locationProvider.html5Mode(true);
});
Now, testing that, localhost:9000/about will load, but when I try to link the state to the navbar it breaks.
'use strict';
angular.module('sr388App')
.controller('NavbarCtrl', function ($scope, $location) {
$scope.menu = [{
'title': 'Home',
'link': '/',
'title': 'About',
'link': '/about'
}];
$scope.isCollapsed = true;
$scope.isActive = function(route) {
return route === $location.path();
};
});
The console error is
Uncaught SyntaxError: Duplicate data property in object literal not allowed in strict mode
Here is the navbar html
<div class="navbar navbar-default navbar-static-top" ng-controller="NavbarCtrl">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle" type="button" ng-click="isCollapsed = !isCollapsed">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
sr388
</div>
<div collapse="isCollapsed" class="navbar-collapse collapse" id="navbar-main">
<ul class="nav navbar-nav">
<li ng-repeat="item in menu" ng-class="{active: isActive(item.link)}">
<a ng-href="{{item.link}}">{{item.title}}</a>
</li>
</ul>
</div>
</div>
</div>
I'm certain my fundamental understanding of what's happening (supposed to be happening) is flawed.
I did notice the # is not being added when attempting to load states without changing URL.
<a ng-href="{{item.link}}">{{item.title}}</a>
I thought I had found the problem, and this would fix it
<a ui-sref="{{item.link}}">{{item.title}}</a>
But no dice.
Any advice/suggestions would be greatly appreciated. All I'm really trying to do is to create a simple SPA page based on this
http://i.imgur.com/sZYe15o.png
That would just simply run through a few different view states.
/#about
/#contact etc.
In ui-sref just put the state name instead of the URL/link
ui-sref="about"
Then it will work

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