AngularJS ng-show 2 way binding not working - angularjs

I am new to AngularJS and I have seen others asking similar questions, but the answers are not working for me. Rather than hijacking those questions, I thought I would open one for myself.
I am creating a demo app -- it lists "sites" which can be added to or deleted. I am using the ng-show attribute to display the required html div while hiding the others.
Here is the back-end javascript--
var SiteMaintenanceModule = angular.module("SitesMaintenance", []);
SiteMaintenanceModule.controller("siteCtrl", diveSiteCtrlfn);
function diveSiteCtrlfn($scope) {
// initializing the sites array
$scope.sites = sites;
//initializing the Divs array
$scope.allowedDivs = ["listSiteDiv","addSiteDiv", "editSiteDiv","deleteSiteDiv"];
// setting the first div as selected. This should show the div which lists the sites
$scope.selectedDiv = $scope.allowedDivs[0];
// function to be called with the selected div is to be changed
$scope.setSelectedDiv = function ($divSelectedByUser) {
$scope.selectedDiv = $divSelectedByUser;
}
};
And here is the html
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="SitesMaintenance">
<head>
<title>List of Dive Sites</title>
<link rel="Stylesheet" href="./../zHelpers/bootstrap/css/bootstrap.css" />
<script src="./../zHelpers/angular.min.js"></script>
<script src="./sites.js"></script>
<script src="./SiteMaintenance.js"></script>
</head>
<body ng-controller="siteCtrl">
<!-- Display the list of sites based on the selectedDiv variable-->
<div id="SiteList" ng-show="{{selectedDiv == 'listSiteDiv'}}">
<h3>List of Sites</h3>
<ul ng-repeat="site in sites" ng-model="sites">
<li>{{site.site}} in {{site.location}}</li>
</ul>
</div>
<!-- Display the add site Div based on the selectedDiv variable-->
<div id="AddSite" ng-show="{{selectedDiv == 'addSiteDiv'}}">
<h3>Add New Site</h3>
<div style="display:block; margin:10px">Site: <input id="inputAddSiteName" /></div>
<div style="display:block; margin:10px">Location: <input id="inputAddSiteLocation" /></div>
</div>
<!-- Display the edit site Div based on the selectedDiv variable -->
<div id="EditSites" ng-show="{{selectedDiv == 'editSiteDiv'}}" style="display:block;margin:20px">
Site Name:<input id="InputEditSiteName" />
Site Location:<input id="InputEditSiteLocation" />
</div>
<div id="controls">
<button id="AddNewSiteButton" ng-click="setSelectedDiv('addSiteDiv')">Add Site</button>
<button id="DeleteSiteButton" ng-click="setSelectedDiv('deleteSiteDiv')">Delete Site</button>
<button id="EditSiteButton" ng-click="setSelectedDiv('editSiteDiv')">Edit Site</button>
</div>
</body>
I can set the visible div to whatever I want at the start, by changing the index in the statement "$scope.selectedDiv = $scope.allowedDivs[0];" in the JavaScript.
I change the value of $scope.selectedDiv when any of the buttons on the page are clicked, so as to change the visibility of the divs.
However, the visibility of the divs doesn't change, no matter what the value of $scope.selectedDiv is. In fact, when debugging in chrome, I see that the attribute value of ng-show for each of my divs updates dynamically to "true" or "false" and expected, but the div is still displayed -- the initially invisible divs seems to have a class="ng-hide" attribute, which never changes.
I have tried $scope.$apply() in the JavaScript but that gives errors. Any help would be greatly appreciated.

You don't need to use {{}} interpolation inside ng-show directive directive, it evaluates the expression inside a $scope of your controller directly.
ng-show="selectedDiv == 'addSiteDiv'"
ng-show="selectedDiv == 'listSiteDiv'"
ng-show="selectedDiv == 'editSiteDiv'"

Related

AngularJS- How to handle each button created by ng-repeat

I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.

can we have ng-show and ng-if in one div tag?

Following code snippet does not work
Please suggest any other way of doing it
<html>
`<div id="tablediv" ng-model="ngtable">
<div ng-show="ngtable">
<div ng-if="currentdevicetype == 'condition1'">
<!-- Other code to display contents -->
</div>`
</div>
</div>
</html>
Yes you can, Both are different.
ng-show
sets the display:none of the element when expression evaluates to false while ng-if removes the element from the DOM when the expression evaluates to false
Check out this question to know the differences between ng-show and ng-if & where and How to use them:
When to favor ng-if vs. ng-show/ng-hide?
In your html code , you are using something wrong, because you are using ng-model for a div .
<html>
<div id="tablediv" ng-model="ngtable">
<div ng-show="ngtable">
<div ng-if="currentdevicetype == 'condition1'">
<!-- Other code to display contents -->
</div>
</div>
</div>
</html>
ng-model is used to bind the value of any inputbox/textarea/select like tags, you can not bind any value like this:
<div id="tablediv" ng-model="ngtable">
if you remove this ng-model then your code would be like this:
<html>
<div id="tablediv">
<div ng-show="ngtable">
<div ng-if="currentdevicetype == 'condition1'">
<!-- Other code to display contents -->
</div>
</div>
</div>
</html>
Now, if ngtable have some value it means ng-show=true then
<div ng-show=true>
// all the elements are visible on the DOM.
</div>
but , if if ngtable do not have any value it means ng-show=false then :
<div ng-show=false>
// all the elements are not visible on the DOM.
</div>
And inside this code:
<div ng-if="currentdevicetype == 'condition1'">
<!-- Other code to display contents -->
</div>
if ng-if="currentdevicetype == 'condition1'" returns true then all the elements would be create, otherwise element will not be created.

Opening other element on focus on current one Angular JS

In my controller I have input box and a div with text.
By default div is set to display:none
I want to make div visible by focusing on input box.
Is it possible to do with angular.js
Try this (No need to set you div display:none, initally showDiv is false and your div will be hidden):
<body ng-controller="myController" ng-init="showDiv=false">
<input type="text" ng-focus="showDiv=true">
<div ng-show="showDiv"></div>
</div>
Yea Angular makes it super easy without even having to write anything in controller, here's an example:
https://plnkr.co/edit/OqLpGxWwfPaBTVdTBYDy?p=preview
<body ng-controller="MainCtrl">
<input type="text" ng-hide="show" />
<button ng-click="show = !show">Show / Hide</button>
</body>
Obviously you could make yours on a hover instead of a click but you get the idea.

Angular Bootstrap Tabs Set Active Tab Through Markup

I'm trying to set a tab as active through the markup. For some reason when I set the active attribute on a tab it seems to mangle the state of the tabs. The page loads up fine and the tab that was set as active will be deactivated when clicking another tab. When I click back on the tag that was set with active="true" the previously selected tab will not be deselected.
...
<tab heading="Dynamic Title 1" active="true">Some Title 1</tab>
...
http://plnkr.co/edit/xzDbezXgkSMr6wokov6g?p=info
I switched to creating a variable that is set to true at init and plopped that into the active attribute. I'm hoping there's a better way to this though.
<tabset ng-init="startActive = true">
...
<tab heading="Dynamic Title 1" active="startActive">Some Title 1</tab>
...
</tabset>
http://plnkr.co/edit/mt5MQSZEl730fsMuMxg8
I don't want to define the tabs in js because this is a project that uses webforms and piping data from that to js might be worse than what I'm doing here. I change the page to be completely built with angular in which case piping data like the tab to be selected could be part of some config endpoint that would be hit on the controller's init. I'd rather not have to redesign a complete page to make this change but it seems like the most correct way to go. Any thoughts and tips would be appreciated.
I know this is quite old, but after wasting hours of my life, I came up with a super dirty hack, that does the trick (assuming I understood your question correctly and you have the same issue as me).
Problem Statement
Using UI Bootstrap Tabs, dynamically adding tabs based on list data and maintaining the active state outside of this data.
When using the Tabs of UI Bootstrap and generating tabs like this:
<tab ng-repeat="item in page.data.list" active="item.active">
UI Bootstrap will use the binding of the item to store the active state. If we omit the active attribute, UI Bootstrap will maintain it internally but then it becomes impossible to manipulate the active state from the outside, except for accessing it via one of these: $$ (which are the untouchables!)
Solution (The Hack)
Maintain the active state in another list:
<div ng-controller="parasample-tabs">
{{activeState}}
<tabset ng-show="page.data.list.length">
<tab ng-repeat="item in page.data.list" active="activeState[$index]">
<tab-heading>
<i style="cursor: pointer" class="glyphicon glyphicon-remove" ng-click="delTab($index)" prevent-default></i>
Item {{$index +1}}
</tab-heading>
{{item.text}} - {{item.transcript}} - {{item.active}}
</tab>
</tabset>
<!--
For me this problem arose because I like to use self-contained, self-managing data
from factories, hence I call addItem not on a controller
-->
<button ng-click="page.addItem()">Add Item</button>
</div>
Now for the controller, that is wrapped around that tabs and manages them, and their active state instead of writing it into my data:
app.controller('parasample-tabs', function ($scope) {
$scope.maxItems = 5;
$scope.activeState = [];
$scope.delTab = function (idx) {
var list = $scope.page.data.list;
if (list.length > 0) {
$scope.page.delItem(idx);
$scope.activeState.splice(idx, 1);
}
};
$scope.$watch(
"page.data.list.length",
function (newLen, oldLen) {
if (!newLen) return;
// new item => new tab, make active
if (newLen > oldLen)
$scope.activeState.push("true");
}
);
});
Now UI Bootstrap will access the array activeState and store the active state there. There is no need for initialisation, as that is taken care of.
When a new item is added to our data list, the watch will set the new tab as the active tab (thats my preference) and the rest of the list will be updated by UI Bootstrap.
When deleting however, it is not easily possible to determine which item was removed, so I had to wrap my page.delItem into the controller's delTab method.
Here is a fiddle to play with, too.
Let's hope that UI Bootstrap will allow for a different way to maintain the active state instead of having a two way binding in the active attribute. I like having an "active ID" variable.
Disclaimer: I am aware of how dirty this is and I only tested it in Chrome so far and it works nicely.
You're missing quite a few here. Here's a more extensible way:
var app = angular.module('myApp',[]);
app.controller('MyController', ['$scope',function($scope){
$scope.tab = 0;
$scope.changeTab = function(newTab){
$scope.tab = newTab;
};
$scope.isActiveTab = function(tab){
return $scope.tab === tab;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<style type="text/css">
.active{
background-color:red;
}
</style>
</head>
<body ng-controller="MyController">
<div>
<div ng-class="{'active':isActiveTab(0)}" ng-click="changeTab(0)">Some Title 1</div>
<div ng-class="{'active':isActiveTab(1)}" ng-click="changeTab(1)">Some Title 2</div>
</div>
<br/>
<div ng-show="isActiveTab(0)">tab1</div>
<div ng-show="isActiveTab(1)">tab2</div>
<script type="text/javascript" src="js/angular-1.2.24.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
Initialization should always be in the controller.
Change the values using a controller function. Here, defined as 'changeTab()'
For checking active tabs, create a controller function to compare if the current value of $scope.tab is equal to the current tab.
I also added a bit of styling to impose which tab is active.

[Angular JS]- Tabs Pane Example - Dynamic Add Tab

I have used the example from Angular JS Homepage and modified it to meet the requirements.
I have added the tabs info in a scope array and manipulate the data based in some conditions.
Issues:
I have attached an ng-bind on tabItem.title, so any change in the text box will update the title, but i want to limit the displaying of the title by 10 chars
When i create a new tab, i want that tab to be the selected one.
How can i select a tab based on some action taken (like on a click move from tab 1 to tab 2)
Fiddle: http://jsfiddle.net/austinnoronha/NWwcT
<br/><br/>
<div ng-cloak ng-app="TabsApp">
<div class="container" ng-controller="TabManagerCtrl">
<span class="label label-info label-ext" ng-click="tabManager.addTab()" style="cursor:pointer">Add a Tab</span><br/><br/>
<div>
<div tabs>
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
<p>{{ tabInfo.content }}</p>
<input type="text" ng-model="tabInfo.title" ng-change="tabManager.getTitle(tabInfo)">
</div>
</div>
</div>
<br/><br/><br/>
</div><!-- /container -->
</div> <!-- /container -->
</div> <!-- /app -->
that's strange...
The limitTo filter doesn't seem to work, but you can create a new one and change your line
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
by
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title | limit:10}}">
with
angularApp.filter('limit', function() {
return function (input, value) {
return input.substr(0,value);
};
});
For the select one, I think it doesn't work because you have to have access to the pane scope. One way to do it is to access to access the property from the pane when you create it. In the pane directive, just add :
if(scope.$parent.tabInfo.selected) tabsCtrl.select(scope);
just after the tabsCtrl.addPane(scope); line. But then you also have to change the tabs directive so that the line
$scope.select = function(pane) {
become
this.select = $scope.select = function(pane) {
For your 3rd question, I don't know how to do it in that scheme.
I would make the pane directive different, putting the select function out of the directive, and binding it directly to your tabManager object.
Like this : http://jsfiddle.net/NWwcT/2/
In this cas, you have the 3 requirements, and you can select the tab from ouside by calling tabManager.select(index)

Resources