Allow only one collapse div in ng-repeat - angularjs

I have some data in the ng repeat, and inside that I have some data under each divs which is collapsed.
No when I click on the main div, I want only one div to collapse in at a time.
Eg: if I click abc, asdasd should be displayed.. Then if I click abc1, asdasd1 should be displayed but NOT asdasd
<script>
angular.module('myApp', [])
.controller("Ctrl_List", ["$scope", function(s) {
s.people = [
{name:"Sten", age:"49"}
,{name:"John", age:"39"}
,{name:"Hanne", age:"37"}
,{name:"Jens", age:"37"}
,{name:"Brian", age:"24"}
,{name:"Johnny", age:"24"}
,{name:"Peter", age:"49"}
]
s.obj = [
{
"name":'abc',
"text":'asdasd'
},
{
"name":'abc1',
"text":'asdasd1'
}
]
}])
html:
<body ng-app="myApp" ng-controller="Ctrl_List">
<div ng-repeat="ob in obj">
<button class="btn" data-toggle="collapse" href="#abc-{{ob.name}}"> {{ob.name}}</button>
<div id="abc-{{ob.name}}" class="collapse">{{ob.text}}</div>
</div>
</body>
data-parent is not working for me, or may be I am not using it properly.
Please Check the Fiddle here

Using a pure Angular approach rather than using JQuery for this.
Add a new property show to the each object and use ng-if to show/hide its corresponding text using a method in controller.
<div ng-repeat="ob in obj">
<button class="btn" ng-click=" showThis(ob)"> {{ob.name}}</button>
<div ng-if="ob.show">{{ob.text}}</div>
</div>
controller method
s.showThis = function(obj) {
//Hides all
angular.forEach(s.obj, function(ob) {
if(ob.name != obj.name) {
ob.show = false;
}
});
//Toggles current object show/hide
obj.show = !obj.show;
}
Working Fiddle

Related

AngularJS hide any parent div using ng-click in a child element

I already know about ng-if and ng-show methods of showing/hiding DOM elements. In this case, however, I have about 100 div elements, each with multiple child span elements, and whenever a span is clicked, I want the parent div to hide.
Example:
<div>Display text
<span ng-click="hideThisDiv(this)">Option1</span>
<span ng-click="hideThisDiv(this)">Option2</span>
<span ng-click="hideThisDiv(this)">Option3</span>
</div>
In the function, I want to be able to do something like:
$scope.hideThisDiv = function(element){
element.$parent.$id.visible = false;
}
Using console.log(element.$parent) in this function shows, however, that there isn't a simple way to access a "visible" property of this div element. At least, not that I can see so far.
This seems like a simple concept, I'm just lacking the proper syntax or access method.
Try below code it works
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope) {
$scope.hideParent = function (event) {
var pEle = event.currentTarget.parentElement;
pEle.style.visibility = "hidden";
}
});
<!DOCTYPE html>
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-controller="MainCtrl">
<div>
This is parent div click below to hide <br />
<span ng-click="hideParent($event)">Click here to hide</span> <br />
<span ng-click="hideParent($event)">or Here</span><br />
<span ng-click="hideParent($event)">or Here</span>
</div>
</body>
</html>
If you prefer to do this with jquery then use the jqLite approach with angular.element like this:
$scope.hideThisDiv = function(el) {
angular.element(el.target).parent().addClass('hidden');
};
Then pass in the event like this:
<span ng-click="hideThisDiv($event)">Option1</span>
The add this to your css
.hidden {
display:none
}
Solution:
The better approach is to create a custom directive and hide the parent element using jqLite.
var app = angular.module('app', []);
app.directive('hideParentOnClick', function () {
return {
link: function (scope, element) {
element.on('click', function () {
element.parent().css({display: 'none'});
});
}
}
});
And in your HTML:
<div>
Display text
<span hide-parent-on-click>Option1</span>
<span hide-parent-on-click>Option2</span>
<span hide-parent-on-click>Option3</span>
</div>
Plunker Example
Advantages:
You can combine this directive with the aforementioned ng-click because the last one is not utilized in this method and can be freely used for any other purpose.
Directives are intended for DOM manipulations, not controllers. Read more here.
Better overall modularity.

How to use $event only for parent element in Angular JS?

I have HTML code with ng-click event:
<div class="btn share" ng-click="do($event)">
<span">1</span>
</div>
Angular JS:
$scope.do = function (event) {
var target = angular.element(event.target);
var parsed = parseInt(target.find('span').text(), 10);
}
When I click to element div or child element span is called event do().
But if I click on span my counter inside span is not increment. Only by clicking parent element div.
How I can set same $event for div and span elements?
I would recommend to work with scope bindings instead of DOM textContent:
<div class="btn share" ng-click="do()">
<span>{{count}}</span>
</div>
and in controller
$scope.count = 0;
$scope.do = function () {
$scope.count++;
};
If you however still want to know why it failed with your approach, it's because you need to use currentTarget, not just target:
angular.module('demo', []).controller('MainCtrl', function($scope) {
$scope.do = function(event) {
var target = angular.element(event.currentTarget);
var parsed = parseInt(target.find('span').text(), 10);
target.find('span').text(parsed + 1);
};
});
<script src="https://code.angularjs.org/1.4.3/angular.js"></script>
<div ng-app="demo" ng-controller="MainCtrl" class="btn share" ng-click="do($event)">
<span>1</span>
</div>
But don't do this, controller should not work with DOM at all, this is
not what controllers are for.
You're doing it the wrong way. Angular is not jQuery. You shouldn't do any DOM manipulation in the controller. The view should be generated based on the model, and not vice-versa.
The code should be
<div class="btn share" ng-click="do()">
<span>{{ counter }}</span>
</div>
and in the controller:
$scope.counter = 1;
$scope.do = function() {
doSomethingWithCounter($scope.counter);
}
Have you tried adding the same click event to your span also?
Like this
<span ng-click="do($event)"> 1 </span>

Bootstrap popover not working inside AngularJs ng-repeat

I have a countries list and I am populating those using ng-repeat, everything is working fine. Also, I am trying to show some other details inside each country by using the bootstrap popover and it doesn't seem to work so can someone please help me?
Html Code:
<body ng-app="app" ng-controller="my_controller">
<div class="span3 projectCard" ng-repeat="country in all_countries">
<div class="projectCardHeight">
<button class="btn close cardClose" ng-click="deleteCountry(country.id)">×</button>
<div class="cardHeader">Country</div>
<div class="cardBody">{{country.id}}</div>
<div class="cardBody">{{country.title}}</div>
<div class="cardBody">pop</div>
</div>
</div>
</body>
Javascript Code:
var app = angular.module("app", []);
app.controller('my_controller', function($scope) {
$scope.all_countries = [
{"id":28,"title":"Sweden"},
{"id":56,"title":"USA"},
{"id":89,"title":"England"}];
});
function deleteCountry(id)
{
alert("Do something");
}
$(document).ready(function () {
$("a[rel=popover]")
.popover({ placement: 'bottom', html: 'true' })
.click(function (e) {
e.preventDefault();
});
});
Please refer to this JsFiddle
Demo: http://jsfiddle.net/5ww8e/1/
Create a new directive called bs-popover and apply it together with ng-repeat. Trigger popover method inside bs-popover directive.
Also your js file loading order is wrong, you should load jquery before bootstrap.

Display list of items and edit them via AngularJS

I try to solve a classic problem using AngularJS: I need to display list of some entities and provide ability to add, edit and view details of this entities.
I implement two controllers: ListController to iterate list of entities and ItemController to display and save entity details. This is html code:
<div ng-app="myApp">
<a class="btn" data-toggle="modal" data-target="#modal">Add new item</a>
<div ng-controller="ListController">
<h4>List</h4>
<ul>
<li ng-repeat="item in list">
{{item.name}}
<a class="btn" data-toggle="modal" data-target="#modal" ng-click="editItem(item)">Edit item</a>
</li>
</ul>
</div>
<div id="modal" role="dialog" class="modal hide fade">
<div ng-controller="ItemController">
<div class="modal-header">
Item Dialog
</div>
<div class="modal-body">
<label for="txtName" />
<input type="text" id="txtName" ng-model="item.name" />
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="saveItem()" data-dismiss="modal">OK</button>
</div>
</div>
</div>
and controllers code:
var db_list = [{ name: "Test1" }, { name: "Test2" }];
var app = angular.module('myApp', []).
controller('ListController', function($scope, $rootScope) {
$scope.list = db_list;
$scope.editItem = function(item) {
$rootScope.item = item;
}
}).
controller('ItemController', function($scope, $rootScope) {
$scope.saveItem = function() {
db_list.push($rootScope.item);
$rootScope.item = null;
}
});
Also you can find the working ptototype at http://jsfiddle.net/yoyoseek/9Qntw/16/.
The general problem in this code that I store entity to display its description using scope of the ListController (via editItem()), but I need this stored entity details in the ItemController. I use $rootScope for sharing entity to edit and it looks like hack for me. Is it a normal practice?
This code has one more drawback: $rootScope.item have to been cleared on modal dialog hide.
It looks like the main problem here is that events triggered by data-toggle happen outside of your control and it's not part of the AngularJS bindings (I am new to it so I may be wrong).
Anyway, it seems like there is no way to cross-reference controllers in Angular, and the only way to get hold of them is via inspecting the DOM. But, once you get into that, you may as well initialize the scope directly (http://jsfiddle.net/B4kAW/4/):
var db_list = [{ name: "Test1" }, { name: "Test2" }];
var app = angular.module('myApp', []);
app.controller('ListController', function($scope) {
$scope.list = db_list;
$scope.editItem = function(item) {
angular.element(document.getElementById("modal")).scope().item = item;
};
});
app.controller('ItemController', function($scope) {
$scope.saveItem = function(item) {
//db_list.push(item);
//$rootScope.item = null;
};
});
Note:
The modal dialog here has no way of knowing whether it's opened for editing, or adding a new item (I commented out push).
Since the dialog is linked with "main" item in the list, it updates it instantly (can be seen while the dialog is open, on the background). You may need to copy it instead of using a reference.
Inspired by this answer. It looks like "the Angular way" around dialogs is to convert them into services.

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