Angular add class to body from inside view - angularjs

I have an app where, when a thumbnail is clicked a modal will open and play the video connected to the thumbnail. What I need to do is add a class to the body tag when this modal is open so I can stop the body content scrolling behind the modal.
I am using an ng-click to activate an ng-show and ng-if. The problem is all of this is inside the scope of an ng-repeat which in turn is inside the view. I am new to Angular and any help would be appreciated.
<div class="videos" ng-controller="modalCtrl">
<ul>
<li class="clear-fix" ng-repeat="video in filtered = videos | filter:search | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
<!-- THIS ACTIVATES THE MODAL WHEN CLICKED -->
<div ng-click="showModal = !showModal" class="item-thumbnail float-left pointer" back-img="{{video.thumbnail}}">
</div>
<div class="item-details-container float-left">
<div class="item-header">
<div ng-click="showModal = !showModal" class="item-title pointer">
<h3 class="underline">{{video.title}}</h3>
</div>
<div class="item-author pointer">
<span>by: <a class="underline" ui-sref="{{video.author_link}}">{{video.author}}</a></span>
</div>
</div>
<div class="item-description">
<p>{{video.description.trunc(150)}}</p>
</div>
</div>
<!-- THIS IS THE MODAL BACKGROUND COVER -->
<div ng-show="showModal" class="modal-cover"></div>
<!-- THIS IS THE MODAL -->
<div ng-show="showModal" class="modal-container">
<div ng-if="showModal" class="video-modal clear-fix">
<button class="btn-close" ng-click="$parent.showModal = false">
<span></span>
<span></span>
</button>
<div class="video-container float-left">
<youtube-video video-url="video.url"></youtube-video>
</div>
<div class="video-info-container float-right">
<div class="video-info">
<div class="item-header">
<div class="item-title">
<h3>{{video.title}}</h3>
</div>
<div class="item-author pointer">
<span>by: <a class="underline" ui-sref="{{video.author_link}}">{{video.author}}</a></span>
</div>
</div>
<div class="item-description">
<p>{{video.description}}</p>
</div>
</div>
<div class="voting-container clear-fix">
<div class="votingButton btn-solid pointer" ng-click="upVote(video); showDetails = !showDetails">
<i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
</div>
<div class="bugButton btn-solid pointer">
<i class="fa fa-flag-o" aria-hidden="true"></i>
</div>
<div ng-show="showDetails = showDetails"><span>Thank you for voting.</span></div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>

Here's what you need to do :
You can use ng-class in your body tag like this
<body ng-class="{'is-modal-open': freeze}">
And you can write ng-click on your thumbnail like this
<div class="thumbnail" ng-click="is-modal-open=true"></div>

You could just make a div in your template like this:
<div class="fullscreen-modal">
//content here
</div>
And in your controller you could do this:
var elementResult = element[0].getElementsByClassName('fullscreen-modal');
angular.element(document.body).append(element);
Now your element is a direct child of <body>.
OR
Define the modal div outside of ng-repeat.
Then define a scope function
$scope.openModal() = function(contentOrVideoId)
{
//put logic here
$scope.showModal = true;
$scope.modalContent = contentOrVideoId;
}
And just call this function inside ng-repeat with ng-click="openModal('IdOrContent')"

You are looking for ngClass directive.
So if you would add this to the body element you want to disable scrolling on, it would give you what you are looking for:
<div ng-class="{'is-modal-open': showModal}">
In short, this will add the class is-modal-open when showModal validates to true
Just to clarify (Thanks #Ronnie), you need to make sure the <div> that contains what you call body is inside the scope of your controller (somewhere inside the div that has ng-controller). And you shouldn't put it directly on the <body> tag
[edit]
I don't like using $rootScope, but you could try this:
<body ng-class="{'is-modal-open': showModal}">
// Your div
<div ng-click="showHideModal()" class="item-title pointer">
// your controller
app.controller('modalCtrl', ['$scope', '$rootScope', function($scope, $rootScope) {
$scope.showHideModal = function() {
$rootScope.showModal = !$rootScope.showModal;
};
}]);

Related

controller scope not working in separate html page

I tried to hide some menus using a controller. Here is my element container where the menu will be loaded.
<div class="page-content" ng-controller = "menuController">
<div id="Menu" > </div>
<div ng-view> </div>
</div>
<script>
$(function(){
$("#Menu").load("Menu.html");
});
app.controller("menuController", function($scope) {
$scope.showMenu = false;
});
</script>
I wrote the menu in seperate html file.
<div class="category-content no-padding">
<ul ng-show= "showMenu">
<li><i class="fa fa-h-square text-brown" aria-hidden="true"></i><span>Organization</span>
</li>
<li><i class="fa fa-hospital-o text-brown" aria-hidden="true"></i><span>Clinic</span>
</li>
<li><i class="fa fa-user text-brown" aria-hidden="true"></i><span >User</span>
</li>
</ul>
</div>
But for me scope variable declared in the controller does not have any impact on menu. Please help me to overcome this.
Thanks for your valuable time.
Mixing Jquery code with Angular code is not very good.
You can use angular's ng-include directive to load your menu:
<div class="page-content" ng-controller = "menuController">
<div ng-include="'Menu.html'" > </div>
<div ng-view> </div>
</div>
Depending on the location of Menu.html, you may have to precise the entire path, for example:
<div> ng-include="'folder/subfolder/Menu.html'" </div>

How to access a ngform name from controller?

I need to check if the elements on the current html page (being rendered using ui-view) are dirty or pristine before I navigate to next tab.
Parent page:
<div class="inner-menu">
<nav>
<div>
<ul class="nav nav-tabs edit-menu" role="tablist">
<!-- location 1 -->
<li ng-repeat="innerTab in innerTabListArr" ng-click="switchTab($index, $event)">
<a role="tab" data-toggle="tab" href="">{{innerTab.text}}</a>
</li>
</ul>
</div>
</nav>
<div ui-view="innerTabHolder" name="currForm"></div>
</div>
and the HTML template that will be rendered to innerTabHolder view is :
<div class="edit-general" id="General">
<div class="modal-dialog modal-lg">
<form class="form-horizontal" name="generalForm">
<label for="inputL3" class="control-label">Text</label>
<div class="col-sm-4">
<input type="text" class="form-control" ng-model="gn.myMdl">
</div>
<div class="box-footer">
<div class="row">
<div class="col-sm-10">
<!-- location 2 -->
<button class="btn" type="button" ng-click="switchTab(generalForm, $event)"> BCK </button>
<button class="btn" type="button" ng-click="saveGen()">Save Above</button>
<button class="btn" type="button" ng-click="switchTab(generalForm, $event)"> FWD </button>
</div>
</div>
</div>
</form>
</div>
</div>
There are multiple tabs that will get rendered into the view. And this is the controller I have:
myApp.controller('compTabCtrl',[ '$rootScope', '$scope', '$state', 'mainWebService',
function($rootScope, $scope, $state, mainWebService){
$scope.innerTabListArr = [{"text" : "Tab 1"},{"text" : "Tab 2"}];
$scope.switchInnerTab = function(tabId, event){
};
}]);
Ok, so this is basic outline and I believe, I have covered all parts. Now, my issue is I am not able to pass the form : "generalForm" into switchTab function at location 1 where as I can do the same at location 2.
I am using the form's $dirty and $pristine to check if the user has made any changes to the form. So, while clicking on the tab for navigation, the form becomes undefined.
How do I access the $dirty property of sub-view in controller.
Plunker for demo :
https://plnkr.co/edit/06F5JfXltinyxrZbbc14?p=preview
When you are trying to access the variable always use $scope
access curForm using
$scope.curForm.$dirty

Angular.js no scope in ng-include html template

I am learning as I go with my first Angular project and have ran into an issue.
Goal: When an link is clicked in a given .html template placed in with ng-include, I want it to change the value of $scope.selectedLocation
The issue: The value of $scope.selectedLocation does not change.
I read that the ng-include creates a child scope, so in order to change the parent scope variable, you could place $parent in front of the value. I have tried this and it does not work.
Main index page:
<body ng-app="photoApp" id="bodyDiv" >
<div ng-controller="PhotoGallery">
<div>
<ng-switch on="selectedLocation" >
<div ng-switch-when="home" >
<div ng-include="'home.html'"></div>
</div>
<div ng-switch-when="loc1">
<div ng-include="'file1.html'"></div>
</div>
<div ng-switch-when="loc2">
<div ng-include="'file2.html'"></div>
</div>
</ng-switch>
</div>
</div>
</body>
home.html code:
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
</div>
photoApp.js code:
var photoApp= angular.module('photoApp', []);
westonPhotographyApp.controller('PhotoGallery', function($scope)
{
$scope.selectedLocation ="home";
}
The issue is that you're binding to a primitive in an inherited scope. To fix it you should pass an object:
westonPhotographyApp.controller('PhotoGallery', function($scope)
{
$scope.vm = {
selectedLocation: "home"
}
}
Html
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="vm.selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="vm.selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
ng-include creates a new scope that inherits the parent (controller) scope through the prototype chain. In javascript you can't replace the value of the shadowed inherited property. Passing an object works as you're changing a property on a pointer to the object.
https://github.com/angular/angular.js/wiki/Understanding-Scopes
You seem to have misnamed your app variable. Either name westonPhotographyApp photoApp or vice-versa:
var photoApp = angular.module('photoApp', []);
photoApp.controller('PhotoGallery', function($scope) {
$scope.selectedLocation ="home";
}
Anyways, you could improve on your design:
You could use controllerAs syntax. It names your controller and makes it accessible throughout descendant scopes:
Index:
<div ng-controller="PhotoGallery as pgCtrl">
<div>
<ng-switch on="selectedLocation" >
<div ng-switch-when="home" >
<div ng-include="'home.html'"></div>
...
Home:
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="pgCtrl.selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="pgCtrl.selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
</div>
With your controller:
photoApp.controller('PhotoGallery', function() {
var vm = this;
vm.selectedLocation ="home";
}

Mobile Angular UI modal not able to update

Seems like modals in Angular UI is difficult to update, previously in Bootstrap I could update via jQuery but in Angular UI, not able to do even a simple update.
I have <span id="spnApproveSelectedCount">0</span> inside my modal-body, and I update it using jQuery $('#spnApproveSelectedCount').text(selectedCount); like this. It was working in Bootstrap but not in Angular UI.
Even update from $scope is not working if that variable is inside the modal. But if I moved them outside of modal it is working. I suspect it is because the modal is not display yet?
Updated:
I have a repeat in which the each item is clickable. When user clicked on it, it's supposed to open up the modal with further info. Below are my codes.
<div class="list-group">
<div ng-repeat="approval in approvals" class="list-group-item">
<div class="row">
<div class="selectable" style="float: left; width: 95%" ui-turn-on="detailsModal" ng-click="SetDetails(approval)">
<p class="list-group-item-text"><b>Ref</b> <span>{{ approval.ref }}</span></p>
<p class="list-group-item-text"><b>Pay To</b> <span>{{ approval.payTo }}</span></p>
<p class="list-group-item-text"><b>From</b> <span>{{ approval.from }}</span></p>
</div>
</div>
</div>
</div>
Notice that I have the ng-click on the row and below are my codes at controller.
$scope.SetDetails = function(current)
{
$scope.details = current;
}
And also partial of my modal code..
<div class="modal" ui-if="detailsModal" ui-state='detailsModal'>
<div class="modal-backdrop in"></div>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" ui-turn-off="detailsModal">×</button>
<h4 class="modal-title">Transaction Details</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-sm-5">
Type
</div>
<div class="col-sm-7">
<b>{{ details.category }}</b>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-5">
Submitted By
</div>
<div class="col-sm-7">
<b>{{ details.submittedBy }}</b>
</div>
</div>
Before everything, in fact in my controller I have a line of code to pre-set the details variable to take the first element (before it is passed to ng-repeat), this works and when the modal open, it is showing the first element value and that's it, the value stays there even if I click on row 2, 3 ...
$scope.details = $scope.approvals[0];

Using ng-click inside np-repeat

I'm trying to implement a shortlisting functionality in a case where I'm using ng-click inside ng-repeat.
While the $index is being displayed correctly outside the ng-click, $index is only the index of the last object in the JSON array in all the cases where the html is generated using ng-repeat.
I was expecting the respective venue or venue.id to be passed as an argument to shortlistThis(). I'm guessing that this could be an issue related to event binding.
Can someone help me understand what's going wrong here and probably a better way to do this if possible.
I did try checking this Bind ng-model name and ng-click inside ng-repeat in angularjs The fiddle here works just fine but, mine doesn't.
Update: I've found something interesting here. When the shortlist button is placed just under the ng-repeat, it work just as intended. But when, nested inside a div with a ng-class, it isn't working as intended. Can anyone explain and suggest a fix for this ?
//locationsapp.js var locationsApp = angular.module('locationsApp', []);
var venues = [{
id: "Flknm",
name: "ship",
}, {
id: "lelp",
name: "boat",
}, {
id: "myp",
name: "yacht",
}, ];
var shortlistedVenues = [];
var locationsApp = angular.module('locationsApp', ['ui.bootstrap']);
locationsApp.controller("getvenues", function($scope) {
$scope.venues = venues;
$scope.shortlistThis = function(venue) {
console.log(venue);
if (shortlistedVenues.indexOf(venue) == -1) {
shortlistedVenues.push(venue);
//alert('If');
} else {
console.log('already shortlisted')
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="locations" ng-app="locationsApp">
<div ng-controller="getvenues">
<div ng-repeat="venue in venues" ng-mouseover="" class="venue">
<div ng-controller="manageInfo">
<div class="row-fluid">
<div class="control" ng-click="showInfo()">
</div>
<div class="maps" class="info">
<div ng-class="class">
<div class="close-info" ng-click="hideInfo()">
<i class="fa fa-times">
</i>
</div>
<div class="row full-venue-contents" ng-app="ui.bootstrap.demo">
<div class="">
<div class="row-fluid myclass">
<div class="button-holder">
<div class="row-fluid">
<div class="col-md-4 col-xs-4 text-center btn-grid">
<button type="button" class="btn btn-default btn-lg btn-sup" ng-click="shortlistThis(venue)">
Shortlist{{$index}}
</button>
</div>
</div>
</div>
</div>
</div>
<!-- End of Full Info Container -->
</div>
</div>
</div>
</div>
<div class="compare">
<button type="button" class="btn btn-default btn-lg btn-sup">
Compare ( {{shortlistedVenues.length}} )
</button>
</div>
</div>
</div>
</div>
</div>
The problem is with your button div which was position: fixed, it is actually showing the 1st button but clicking on it firing last button click, I'd suggest you should suggest you render only the shortlist button which has been selected by you. For that you can use ng-if and render those button which index is the same as that of selected $index
HTML
<div ng-if="selected==$index" class="button-holder">
<div class="row-fluid">
<div class="col-md-4 col-xs-4 text-center btn-grid">
<button type="button" class="btn btn-default btn-lg btn-sup"
ng-click="shortlistThis($parent.$index)">Shortlist{{$index}}</button>
</div>
</div>
</div>
& then put ng-click="selected='$index'" on ng-repeat div like
<div ng-repeat="venue in venues" class="venue" ng-click="selected=$index">
Working Fiddle
Hope this could help you, Thanks.

Resources