How to make expand and collapse manually child wise in angularjs - angularjs

I have an accordion expand is working fine but collapse is not working,it should work like accordion,for ex when I click 'title 2' its content should expand and 'title 1' content should collapse.below is my code,I am new to angularjs.Anyone can help me.If its in jquery also fine.
HTML
<link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css'>
<body ng-app="app">
<h1>Dynamic accordion: nested lists with html markup</h1>
<div ng-controller="AccordionDemoCtrl">
<div>
<div ng-repeat="group in groups">
<div class="parents" ng-click="item=1"><i class="glyphicon-plus"></i> {{ group.title }}
</div>
{{ group.content }}
<ul class="childs" ng-show="item==1">
<li ng-repeat="item in group.list">
<span ng-bind-html="item"></span>
</li>
</ul>
</div>
</div>
</div>
</body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.4/angular-filter.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-sanitize.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.js'></script>
<script src="js/index.js"></script>
index.js
angular.module('app', ['ui.bootstrap','ngSanitize','angular.filter']);
angular.module('app').controller('AccordionDemoCtrl', function ($scope) {
$scope.oneAtATime = true;
$scope.groups = [
{
title: 'title 1',
isOpen: true,
list: ['<i>item1a</i> blah blah',
'item2a',
'item3a']
},
{
title: 'title 2',
list: ['item1b',
'<b>item2b </b> blah ',
'item3b']
},
{
title: 'title 3',
},
{
title: 'title 4',
},
{
title: 'title 5',
}
];
});

I suggest you those functions :
$scope.open = function (index) {
$scope.groups[index].isOpen = !$scope.groups[index].isOpen;
$scope.closeOthers(index);
}
$scope.closeOthers = function (index) {
for(var i = 0; i < $scope.groups.length; i++) {
if (i !== index)
$scope.groups[i].isOpen = false;
}
}
open is fired when clicking on a parent, closeOthers is called in open. I init a visible boolean to parents. Each time user clicks on a parent, it set visible to true, and others to false.
<div ng-controller="AccordionDemoCtrl">
<div>
<div ng-repeat="group in groups track by $index">
<div class="parents" ng-click="open($index)"><i ng-class="{'glyphicon-minus': group.isOpen, 'glyphicon-plus': !group.isOpen}"></i> {{ group.title }}
</div>
{{ group.content }}
<ul class="childs" ng-show="group.isOpen">
<li ng-repeat="item in group.list">
<span ng-bind-html="item"></span>
</li>
</ul>
</div>
</div>
</div>
Working demo

Related

Save the click on a method

How can i save the titles selecteds of a ng-click in a method in controller?
<div ng-click="selectItem(dimension, $event)">
<span text="{{dimension.title}}" title="{{dimension.title}}">Item 1</span>
</div>
<div ng-click="selectItem(dimension, $event)">
<span text="{{dimension.title}}" title="{{dimension.title}}">Item 2</span>
</div>
<div ng-click="selectItem(dimension, $event)">
<span text="{{dimension.title}}" title="{{dimension.title}}">Item 3</span>
</div>
I am editing a qlik sense extension and need to save the selections in the app.
A better idea would be to identify objects with a unique identifier rather than a title that can be repeated. If the dimension object has an ID(or some other unique value) use it.
Adapt code below to your needs:
var app = angular.module("myModule", []);
app.controller("myCtrl", function($scope) {
var vm = this;
vm.dimensions = [
{
title: 'Title 1'
},{
title: 'Title 2'
},{
title: 'Title 3'
},{
title: 'Title 4'
},{
title: 'Title 5'
},{
title: 'Title 6'
},
];
vm.selected = [];
vm.selectItem = function(item, event) {
if(!vm.isSelected(item)) {
vm.addItem(item);
} else {
vm.removeItem(item);
}
// Show selected list
console.log(vm.selected);
}
vm.isSelected = function(item) {
return vm.selected.indexOf(item.title) != -1;
}
vm.addItem = function(item) {
vm.selected.push(item.title);
}
vm.removeItem = function(item) {
var index = vm.selected.indexOf(item.title);
vm.selected.splice(index, 1);
}
});
.element {
margin: 20px;
line-height: 10px;
border-bottom: 1px solid black;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myModule">
<div ng-controller="myCtrl as ctrl">
<div ng-repeat="dimension in ctrl.dimensions" ng-click="ctrl.selectItem(dimension, $event)">
<span text="{{dimension.title}}" title="{{dimension.title}}" class="element">
{{ dimension.title }}
<span ng-if="ctrl.isSelected(dimension)">- checked</span>
</span>
</div>
</div>
</div>

ng-model into ng-repeat Angularjs

I'm asking if is possible to do something as that in angular
<div ng-app="app">
<div ng-controller="mainController">
<ul ng-repeat="movie in movies |searchFilter:Filter.genre | searchFilter:Filter.name |searchFilter:Filter.pic ">
<li>{{movie.name}}</li>
</ul>
<h2>genre</h2>
<div>
<label>Comedy </label><input type="checkbox" ng-model="Filter.genre.Comedy" ng-true-value="Comedy" data-ng-false-value=''/><br/>
</div>
<h2>PIC</h2>
<label>aa</label><input type="checkbox" ng-model="Filter.pic.aa" ng-true-value="ciao" data-ng-false-value=''/><br/>
<h2>Name</h2>
<label>Shrek</label><input type="checkbox" ng-model="Filter.name.Shrek" ng-true-value="The God" data-ng-false-value=''/><br/>
</div>
</div>
i'm creating a checkbox for filter on different fields (size,name,genre)
ill have a list of avaible sizes,names and genres .
The issue is on ng-model and i tried to write it as "Filter.genre.genre.name" or
"Filter["genre"+genre.name]" and also "Filter.genre[genre.name]" but still not work .
the js.file is
var app =angular.module('app', []);
app.controller('mainController', function($scope) {
$scope.movies = [{name:'Shrek', genre:'Comedy',pic:"cc"},
{name:'Die Hard', genre:'Comedy',pic:"aa"},
{name:'The Godfather', genre:'Drama',pic:"ciao"},
{name:'The Godher', genre:'Comedy',pic:"lel"}];
$scope.genres = [{name:"Comedy"},{name:"Action"},{name:"Drama"}];
});
app.filter('searchFilter',function($filter) {
return function(items,searchfilter) {
var isSearchFilterEmpty = true;
//searchfilter darf nicht leer sein
angular.forEach(searchfilter, function(searchstring) {
if(searchstring !=null && searchstring !=""){
isSearchFilterEmpty= false;
}
});
if(!isSearchFilterEmpty){
var result = [];
angular.forEach(items, function(item) {
var isFound = false;
angular.forEach(item, function(term,key) {
if(term != null && !isFound){
term = term.toLowerCase();
angular.forEach(searchfilter, function(searchstring) {
searchstring = searchstring.toLowerCase();
if(searchstring !="" && term.indexOf(searchstring) !=-1 && !isFound){
result.push(item);
isFound = true;
// console.log(key,term);
}
});
}
});
});
return result;
}else{
return items;
}
}
});
if i make 3 different labels for the field Comedy, Action and Drama with ng-models called as
ng-model="Filter.genre.Comedy" ; ng-model="Filter.genre.Action" and ng-model="Filter.genre.Drama"
it work but it doesnt work if i try to write it into ng-repeat . I hope to have been clearer
In this sample i try to handle your question by change the Model of your page.
we have:
list of movies array => $scope.movies = []
dynamic filters array => $scope.genres = [], $scope.years = [] or more
our target:
Create a dynamic filters to search in movies
what we do
$scope.filterHandler = function (key, value) {}
Run when user start searching on input or select, this function help us to create a filter as object by sending key and value which result is {key:value}
$scope.searchTypeHandler = function (type, dependTo) {}
Run when our filters has some array for example genre has genres as dropdown select, this function help us to return the array which depend to the filter.
var app = angular.module("app", []);
app.controller("ctrl", [
"$scope",
function($scope) {
//your options
$scope.movies = [{
name: 'Shrek',
genre: 'Comedy',
year: 2000
},
{
name: 'Die Hard',
genre: 'Action',
year: 2000
},
{
name: 'The Godfather',
genre: 'Drama',
year: 2015
},
{
name: 'The Godher',
genre: 'Comedy',
year: 2017
}
];
$scope.genres = [{
name: "Comedy"
},
{
name: "Action"
},
{
name: "Drama"
}
];
$scope.years = [{
name: 2000
},
{
name: 2015
},
{
name: 2017
}
];
//
$scope.filter = {}
$scope.filterHandler = function(key, value) {
var object = {};
object[key] = value;
$scope.filter["find"] = object;
};
$scope.searchTypeHandler = function(type, dependTo) {
$scope.filter = {};
$scope.filter.searchType = type;
$scope.filter.options = undefined;
if (dependTo != null) {
$scope.filter.options = $scope[dependTo];
}
};
//default
$scope.searchTypeHandler("name");
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<div class="container" ng-app="app" ng-controller="ctrl">
<div class="page-header">
<div class="row">
<div class="col-lg-12">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h4>Movies</h4>
</div>
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6 pull-right">
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
By {{filter.searchType}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-left">
<li><a ng-click="searchTypeHandler('genre', 'genres')">Filter By Genre</a></li>
<li><a ng-click="searchTypeHandler('name', null)">Filter By Name</a></li>
<li><a ng-click="searchTypeHandler('year', 'years')">Filter By Year</a></li>
</ul>
</div>
<input ng-hide="filter.options" type="text" class="form-control" ng-model="filter.query" ng-change="filterHandler(filter.searchType, filter.query)">
<select ng-show="filter.options" class="form-control" ng-model="filter.option" ng-change="filterHandler(filter.searchType, filter.option)" ng-options="option.name as option.name for option in filter.options"></select>
</div>
<!-- /input-group -->
</div>
</div>
</div>
</div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="movie in movies | filter: filter.find">
{{movie.name}} - <label class="label label-info">Ggenre: {{movie.genre}}</label> - <label class="label label-default">Year: {{movie.year}}</label>
</li>
</ul>
</div>

How fire event when item expanded?

I use in my angularjs project bootstrap accordion.
Here is working plunker
When I expand accordion I want to fire function in my controller named fireOnExpand and pass the appropriate Id of the group to the function.
Here is how I use accordion:
<div ng-controller="MainCtrl">
<uib-accordion>
<uib-accordion-group heading="{{group.title}}" ng-repeat="group in groups" ng-init="isOpen = $first" is-open="isOpen">
<uib-accordion-heading>
<span ng-click="fireOnExpand()"></span>
<div class="text-center text-info">
<strong>{{group.title}}</strong>
</div>
</uib-accordion-heading>
{{group.content}} {{test}}
</uib-accordion-group>
</uib-accordion>
Here is items from controller that displayed:
$scope.groups = [
{Id: 5, title: "Dynamic-1", content: "Dynamic Group Body - 1"},
{Id: 8, title: "Dynamic-2", content: "Dynamic Group Body - 2"},
{Id: 1, title: "Dynamic-3", content: "Dynamic Group Body - 3"},
{Id: 3, title: "Dynamic-4", content: "Dynamic Group Body - 4"}];
Here the function in controller that I wont to fire on expand:
$scope.fireOnExpand = function()
{
alert("ParamPamPam");
};
For example:
If accordion item with header text "Dynamic-2" was expanded I want trigger fireOnExpand event handler and pass to the event appropriate Id(i.e. Id=8).
How can I fire function fireOnExpand and pass appropriate Id parameter when accordion item is expanded?
see Event Bubbling
change this
<span ng-click="fireOnExpand()"></span>
<div class="text-center text-info">
<strong>{{group.title}}</strong>
</div>
to
<span ng-click="fireOnExpand(group.Id)">
<div class="text-center text-info">
<strong>{{group.title}}</strong>
</div>
</span>
if you want to execute fireOnExpand on header text only, then move the ng-click to strong tag
<span>
<div class="text-center text-info">
<strong ng-click="fireOnExpand(group.Id)">{{group.title}}</strong>
</div>
</span>
Plunker
angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function ($scope) {
$scope.oneAtATime = true;
$scope.lastSelected= 0;
$scope.firstLoad =false;
$scope.groups = [{
Id:2,
title: "Dynamic Group Header - 1",
content: "Dynamic Group Body - 1"
}, {
Id:52,
title: "Dynamic Group Header - 2",
content: "Dynamic Group Body - 2"
}, {
Id:23,
title: "Dynamic Group Header - 3",
content: "Dynamic Group Body - 3",
},{
Id:78,
title: "Dynamic Group Header - 4",
content: "Dynamic Group Body - 4"
}];
$scope.fireOnExpand = function(id){
if ($scope.firstLoad === false){
if (id !== $scope.lastSelected || $scope.lastSelected !== 0){
$scope.lastSelected = id;
alert(id);
}
else {
alert("Do nothing");
}
$scope.firstLoad = true;
}
else {
if (id !== $scope.lastSelected ){
$scope.lastSelected = id;
alert(id);
}
else {
alert("Do nothing");
}
}
};
});
<!doctype html>
<html ng-app="ui.bootstrap.demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.2.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="AccordionDemoCtrl">
<uib-accordion close-others="oneAtATime">
<uib-accordion-group heading="{{group.title}}" ng-click="fireOnExpand($index)" ng-repeat="group in groups" is-open="$first">{{group.content}}</uib-accordion-group>
</uib-accordion>
</div>
</body>
</html>

AngularJs - UI Bootstrap Popover

Hello I'm using UI boostrap within Angular App
I would like to add Popover using UI boostrap, so this what I did so far:
<a popover popover-template="'tpl.html'" data-img="http://domain.com/img1.jpg" data-title="Link 1 title" data-content = "Link 1 content...">Link 1</a>
<a popover popover-template="'tpl.html'" data-img="http://domain.com/img2.jpg" data-title="Link 2 title" data-content = "Link 2 content...">Link 2</a>
...
<a popover popover-template="'tpl.html'" data-img="http://domain.com/imgn.jpg" data-title="Link n title" data-content = "Link n content...">Link n</a>
And then inject attributes : data-img, data-title, data-content in this template tpl.html:
<div class="popover-content">
<md-card>
<img ng-src="{{$img}}" class="md-card-image" >
<md-card-title>
<md-card-title-text>
<span class="md-headline">{{ $title}}</span>
</md-card-title-text>
</md-card-title>
<md-card-content>
{{ $content }}
</md-card-content>
</md-card>
</div>
Of course it doesn't work :)
My question is : how to inject element a attributes in the template tpl.html?
Please, any help is appreciated
Here's a plnkr showing how to use scope variable in the popover template.
Simplified markup & template:
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="link in links">
<a uib-popover popover-trigger="mouseenter" popover-placement="bottom" uib-popover-template="'tpl.html'" data-img="http://domain.com/img1.jpg" data-content = "Link 1 content...">{{link.label}}</a>
</li>
</ul>
<script type="text/ng-template" id="tpl.html">
<div class="popover-content">
<div>
<img ng-src="http://domain.com/{{link.img}}" class="md-card-image"/>
<div>
<span>{{link.title}}</span>
</div>
<div>{{ link.content }}</div>
</div>
</div>
</script>
Ctrl Code:
app.controller('MainCtrl', function($scope) {
$scope.links = [
{
label: 'Link 1',
title: 'Link 1 title',
content: 'Link 1 content',
img: 'img1.jpg'
},
{
label: 'Link 2',
title: 'Link 2 title',
content: 'Link 2 content',
img: 'img2.jpg'
},
{
label: 'Link 3',
title: 'Link 3 title',
content: 'Link 3 content',
img: 'img3.jpg'
}
];
});

How to handle selected/unselected ng-class to manage a tabbed popover

My code is as follows (the fiddle):
<div ng-controller="myCtrl">
<div ng-model="currentTab" ng-init="currentTab='Tab1'"/>
<div ng-init="popovers = [
{ name: 'Popover1',
displayName: 'Pop over with two tabs',
tabs: [
{ name: 'Tab1',
displayName: 'First tab',
description: ['First tab description']
},
{ name: 'Tab2',
displayName: 'Second tab',
description: ['Second tab description']
}
]
}
]"/>
<b>Tabs in popover</b>
<div
class="popover"
ng-repeat="p in popovers"
>
Popover name: {{p.displayName}}
<div ng-repeat="t in p.tabs"
class="tab"
ng-class="currentTab==t.name?'selected':''"
ng-click="currentTab=t.name"
>
{{t.name}}
</div>
<div ng-repeat="t in p.tabs"
class="tabContent"
ng-class="currentTab==t.name?'selected':''"
>
<p>{{t.displayName}}</p>
</div>
</div>
</div>
There is something I don't get which make the code not working perfectly, as the selected class name is never removed as one click on the tab.
When you want to modify a variable of your parent scope from within a ng-repeat you need to use $parent.currentTab.
Updated Fiddle

Resources