binding data in ng-repeat angularjs - angularjs

*This is my html file where i want to repeat chapters which is a array that looks like
My code gives binds the selected checked boxes only (Index values) to true. But i need the entire list of chapters and their i.d's to be retrieved on submit.
Cannot figure out how to iterate it on nested loops *
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<span ng-repeat="chapter in chapters">
<label><input type="checkbox" name="checkbox" value="{{chapter}} ng-model="escConfigForm.chapters[$index]" >{{chapter.name}}</label><br>
</span>
<input type="submit" id="save" value="Save" />
$scope.chapters = chapterService.getChapters($scope.isbn);
$scope.submit = function(escConfigForm) {
var postData = {
content_items: JSON.stringify({
"#context" : [],
"#graph" : [ {
"#type" : "ContentItemPlacement",
"placementOf" : {
"#type" : "LtiLink",
"text" : escConfigForm.examName,
"mediaType" : "application/vnd.ims.lti.v1.launch+json",
"title" : "Exam Study Center",
"custom" : {
"dueDate" : escConfigForm.examDueDate,
"targetScore" : escConfigForm.examTargetScore,
"chapters" : escConfigForm.chapters
},
"activityType" : "other",
"activityRefId" : $scope.escId
}
} ]
}),
data: $scope.data
};
postForm($scope.postUrl, postData);
var configData = {
"activityRefId" : $scope.escId,
"dueDate" : escConfigForm.examDueDate,
"targetScore" : escConfigForm.examTargetScore,
"chapters" : escConfigForm.chapters
};
console.log($scope.chapters);
JSON file:
[{"name":"Chapter 1: Negative Messages","id":"832115"},{"name":"Chapter 2: Physics","id":"832115"},...]

I would recommend maintaining a list of the selected objects in the controller.
using this post as referenece: How do I bind to list of checkbox values with AngularJS?
I created this fiddle: http://jsfiddle.net/ruwk5r0v/7/
<div ng-app="formExample">
<div ng-controller="ExampleController"> <span ng-repeat="chapter in chapters" ng-click="checkboxChange($index)" ng-checked="selection.indexOf($scope.chapters[$index]) > -1">
<input type="checkbox" name="checkbox" value="{{$index}}" />
{{chapter.name}}
<br>
</span>
<br>
<input type="submit" ng-click="submitForm()" id="save" value="Save" />
<div> <span ng-repeat="chapter in selection">
<span>
{{chapter.name}}
</span>
<br>
</div>
and the js:
angular.module('formExample', []).controller('ExampleController', ['$scope', function ($scope) {
$scope.chapters = [{
"name": "Chapter 1: Negative Messages",
"id": "832115"
}, {
"name": "Chapter 2: Physics",
"id": "832115"
}];
$scope.submitForm = function () {
console.log(selection);
}
$scope.selection = []
$scope.checkboxChange = function(index){
var chapter = $scope.chapters[index];
var idx = $scope.selection.indexOf(chapter);
if (idx > -1){
$scope.selection.splice(idx, 1);
} else {
$scope.selection.push(chapter);
}
}
}]);
here you can very easily implement your submit function, just use the new selection object.
This really should be moved into a directive, but don't have time to write that right now :P

Here I created a controller for the snippet, and added some data to $scope.chapters object, and it is displaying correctly. The values disappear when selected, but that is another issue.
angular.module('myApp', [])
.controller('myCtrl', ['$scope',
function($scope) {
$scope.chapters = [{
name: 'Chapter 1: Negative Messages',
id: "1",
isSelected: false
}, {
name: 'Chapter 2: Physics',
id: "2",
isSelected: false
}];
$scope.submitItems = function(chapters) {
alert(JSON.stringify(chapters));
}
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl">
<span ng-repeat="chapter in chapters">
<input type="checkbox" name="checkbox" value="{{chapter}}"
ng-model="chapter.isSelected" />
{{chapter.name}}
</span>
<br>
<form ng-submit="submitItems(chapters)">
<input ng-model="chapters" type="submit" id="save" value="Save" />
</form>
</div>
</div>
Edit: Updated the code to reflect the OP needs.

Related

AngularJS checkbox avoid counting when uncheck checkBox

Here is my running code in Plunker
I got a bug: When I uncheck the answer, I do not want to count how many times we select this answer? We will only count the number when we check the answer. For example, I check "Yes", I uncheck "Yes", I check "Yes" again, I will only show "Yes" was selected 2 times, instead of 3 times.
I read some posts about this issue, but cannot make it work by using checked property?
<input type="checkbox" ng-change="answerSelected(ans)" ng-model="checkAnswer">{{ans.answer}}
change the ng-model to object property like ng-model="ans.checkAnswer"
<input type="checkbox" ng-change="answerSelected(ans)" ng-model="ans.checkAnswer">{{ans.answer}}
Then change the function like this
$scope.answerSelected = function(checkAnswer) {
if (checkAnswer.checkAnswer) {
checkAnswer.count++;
}
$scope.answerBoxSelected = true;
};
Demo
Just add a check like this,
if (checkAnswer) {
ans.count++;
$scope.answerBoxSelected = true;
}
DEMO
// Code goes here
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
$scope.questions = [{
id: 1,
question: "Do you like Foo?",
answers: [{
answer: "Yes",
count: 0,
id: 1,
question_id: 1
}, {
answer: "No",
count: 0,
id: 2,
question_id: 1
}]
},
{
id: 2,
question: "Do you like Bar?",
answers: [{
answer: "Yes",
count: 0,
id: 1,
question_id: 2
}, {
answer: "No",
count: 0,
id: 2,
question_id: 2
}]
}
]
$scope.question_index = 0;
$scope.answerSelected = function(checkAnswer,ans) {
if (checkAnswer) {
ans.count++;
}
$scope.answerBoxSelected = true;
};
$scope.nextQuestion = function() {
$scope.question_index++;
$scope.answerBoxSelected = false;
};
});
<!DOCTYPE html>
<html>
<head>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div class="form-group" ng-if="question_index < questions.length">
<div ng-repeat="item in questions">
<div ng-if="question_index == $index">
<h2>{{item.question}}</h2>
<div ng-repeat="ans in item.answers">
<input type="checkbox" ng-change="answerSelected(checkAnswer,ans)" ng-model="checkAnswer">{{ans.answer}}
<br>
</div>
<div ng-if="answerBoxSelected" class="alert alert-warning">
<h3>Answer Selection Summary</h3>
<div ng-repeat="ans in item.answers">
<p>
"{{ans.answer}}" Has been selected {{ans.count}}
<span ng-if="ans.count == 0">time</span>
<span ng-if="ans.count > 0">times</span>
<p>
</div>
</div>
<button class="btn btn-info btn-lg" ng-if="answerBoxSelected && question_index < questions.length - 1" ng-click="nextQuestion()">Next Question > </button>
</div>
</div>
</div>
<div class="alert alert-success" ng-if="question_index == questions.length - 1 && answerBoxSelected">
Congratulations! You answered all the questions. Good job!
</div>
</div>
<script src="script.js">
</script>
</body>
</html>
One workaround is to pass the element itself to the answerSelected method, and check its checkAnswer property. We will only increment the count if this property is true.
<input type="checkbox" ng-change="answerSelected(ans, this)" ng-model="checkAnswer">{{ans.answer}}
$scope.answerSelected = function(checkAnswer, elem) {
if (elem.checkAnswer === true) {
checkAnswer.count++;
}
$scope.answerBoxSelected = true;
};
You can call the function conditionally only when the checbox is checked:
<input type="checkbox" ng-change="!checkAnswer || answerSelected(ans)" ng-model="checkAnswer">{{ans.answer}}
When the checkbox is checked, checkAnswer will evaluate to true, and the function will be called.
When the checkbox is unchecked, checkAnswer will evaluate to false, and the function will not be called.
Here's a plunker

Nested ng-repeat causing problems

I have to deal with a situation where there will be a question and its answers will be dynamically generated. The issue is when i add one question and add its answers then when i add another question then it already contains the same answers as above question.
For Example:
Q. Select ice cream flavour
A. Chocolate
B. Vanilla
Now When i Add another question
Q. Select ice cream company
Now, here it shows
A. Chocolate
B. Vanilla
Following is my code :
<div class="col-lg-12">
<div ng-controller="CustomizationCtrlr">
<form name="CustomizationForm" ng-submit="SaveCustomization(CustomizationForm.$valid)" novalidate>
<div>
<div class="inputDiv">
#Html.TextBoxFor(model => model.GroupTitle, new { name = "GroupTitle", ng_model = "QuestionGroup.GroupTitle", #class = "form-control", maxlength = "65", placeholder = "GroupTitle" })
<br />
</div>
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in QuestionItems" >
#Html.TextBoxFor(model => model.QuestionItemText, new { name = "QuestionItemText", ng_model = "QuestionItem.Text", #class = "form-control", placeholder = "Question Item Text", required = "required" })
<button ng-show="showAddQuestionItem(QuestionItem)" ng-click="AddQuestionItem($parent.$index)">Add question item</button>
<br />
</div>
<button ng-show="showAddQuestion(Question)" ng-click="AddQuestion()">Add question</button>
</div>
</div>
<button type="submit" name="btnPost" class="btn save-btn" onclick="ValidateForm()">Save Customizations</button>
</form>
</div>
</div>
And following is my script:
<script>
var app = angular.module('ProductCatalog.controllers', [])
.controller('CustomizationCtrlr', function ($scope, $http) {
$scope.AddQuestionItem = function (parentIndex) {
var newItemNo = $scope.QuestionItems.length + 1 + "-" + parentIndex;
$scope.QuestionItems.push({ 'id': 'qi' + newItemNo });
}
$scope.showAddQuestionItem = function (QuestionItem) {
return QuestionItem.id === $scope.QuestionItems[$scope.QuestionItems.length - 1].id;
};
$scope.QuestionItems = [{ id: 'qi1', Text: '' }];
$scope.AddQuestion = function () {
var newItemNo = $scope.Questions.length + 1;
$scope.Questions.push({ 'id': 'q' + newItemNo });
}
$scope.showAddQuestion = function (Question) {
return Question.id === $scope.Questions[$scope.Questions.length - 1].id;
};
$scope.Questions = [{ id: 'q1', Text: '' }];
})
</script>
You always iterate over the same reference of QuestionItems on your scope.
If you want to connect the answers to the question you need to somehow create unique answer arrays per question
One way to do it is save the answers in the question instance in a property and then ng-repeat that
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in Question.QuestionItems" >
#Html.TextBoxFor(model => model.QuestionItemText, new { name = "QuestionItemText", ng_model = "QuestionItem.Text", #class = "form-control", placeholder = "Question Item Text", required = "required" })
<button ng-show="showAddQuestionItem(QuestionItem)" ng-click="AddQuestionItem($parent.$index, Question)">Add question item</button>
<br />
</div>
And in the JS:
$scope.Questions = [{ id: 'q1', Text: '', QuestionItems: [{ id: 'qi1', Text: '' }] }];
$scope.AddQuestionItem = function (parentIndex, parentQuestion) {
var newItemNo = $scope.QuestionItems.length + 1 + "-" + parentIndex;
parentQuestion.QuestionItems.push({ 'id': 'qi' + newItemNo });
}
The approach you have contains different scope for Questions and QuestionItems. Whenever, you add a new Question, the Question Items is already populated with previous entries from the previous input.
There is a need to change the data structure here, keep an array of questions and a property within an array for the Question Items.
$scope.Questions = [{
"Id": "q1",
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
}]
This way you can have Question and its items grouped together.
See the snippet below, I had to remove the .net controls for the demo purpose, you can replace the input with the razor controls you had earlier.
var app = angular.module("MyApp", []);
app.controller('CustomizationCtrlr', function($scope, $http) {
$scope.Questions = [{
"Id": "q1",
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
}]
$scope.AddQuestionItem = function(ques) {
var newItemNo = ques.QuestionItems.length + 1
ques.QuestionItems.push({
'Id': 'qi' + newItemNo,
"Text": ""
});
}
$scope.showAddQuestionItem = function(QuestionItem) {
return QuestionItem.id === $scope.QuestionItems[$scope.QuestionItems.length - 1].id;
};
$scope.AddQuestion = function() {
var newItemNo = $scope.Questions.length + 1;
$scope.Questions.push({
"Id": "q" + newItemNo,
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
});
}
$scope.showAddQuestion = function(Question) {
return Question.id === $scope.Questions[$scope.Questions.length - 1].id;
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="MyApp">
<div class="col-lg-12">
<div ng-controller="CustomizationCtrlr">
<form name="CustomizationForm" ng-submit="SaveCustomization(CustomizationForm.$valid)" novalidate>
<div>
<div class="inputDiv">
<input type="text" ng-model="QuestionGroup.GroupTitle" placeholder="GroupTitle" />
<br />
</div>
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in Question.QuestionItems">
<input type="text" ng-model="QuestionItem.Text" placeholder="Question Item Text" />
<button ng-click="AddQuestionItem(Question)">Add question item</button>
<br />
</div>
<button ng-click="AddQuestion()">Add question</button>
</div>
</div>
<button type="submit" name="btnPost" class="btn save-btn" onclick="ValidateForm()">Save Customizations</button>
</form>
<pre>{{Questions | json}}</pre>
</div>
</div>
</body>

Adding the input fields dynamically from nested json object in angulajs

var inputs={
'firstname': '',
'lastName':'',
'account':{
'role':'',
'status':''
}
}
This is my model array. I want to display it dynamically in Webpage and by modifying the json array the changes should affect the form too.
Here is the image
UPD:
for your situation, you can use ng-switch to generate elements according to conditions.
Notice(already included in the code snippet):
ng-repeat will generate it's own scope, so your model won't update unless you bind it with the original scope. ref here.
OLD ANSWER:
use ng-model to implement two-way-databinding.
refer the code snippet below:
angular.module("app", []).controller("myCtrl", function($scope) {
$scope.inputs = {
'firstname': 'test first name',
'lastName': 'test last name',
'account': {
'role': 'test role',
'status': 'test status'
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.4/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
<!-- First Name: <input type="text" ng-model="inputs.firstname"><br>
Last Name: <input type="text" ng-model="inputs.lastName"><br> Account Role: <input type="text" ng-model="inputs.account.role"><br>
Account Status: <input type="text" ng-model="inputs.account.status"><br> -->
<div ng-repeat="(key1, value) in inputs" ng-switch="key1">
<div ng-switch-when="account">
<div ng-repeat="(key2, value2) in value">
{{key1 | uppercase}} => {{ key2 | uppercase}}
<input type="text" ng-model="inputs[key1][key2]">
</div>
</div>
<div ng-switch-default>
{{key1 | uppercase}}
<input type="text" ng-model="inputs[key1]">
</div>
</div>
{{inputs}}
</div>
/My html should look like this/
<head>
<script data-require="angular.js#1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<script type="text/ng-template" id="tree-structure">
<label>{{dt}}</label><input type="text" name="" value="{{dt.label}}">
<ul class="childElement">
<li ng-repeat="dt in dt.nodes" ng-include="'tree-structure'">
</li>
</ul>
</script>
<ul class="parentList">
<li ng-repeat="(key, value) in inputs" >
<div ng-repeat="(key1, value1) in value">
<label>{{key1}}</label>
<input type="text" name="" value="{{value1}}">
<!-- <div ng-repeat="(key2, value2) in value1">
<label>{{key2}}</label><input type="text" name="" value="{{value2}}">
</div> -->
</div>
<div ></div>
</li>
</div>
</ul>
</body>
</html>
Some observations :
Your JSON should be formatted properly with type of the field.
If you want to access the object properties as a form fields then it should be structured in a good way so that we can dynamically add the type of the field as well.
[{
name: 'firstName',
type: 'text'
}, {
name: 'lastname',
type: 'text'
}, {
account: [{
name: 'role',
type: 'text'
}, {
name: 'status',
type: 'text'
}]
}]
As your JSON have nested objects. So, first iterate it recursively and create one dimensional array then create the fields using 1D array.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
var inputs = [{
name: 'firstName',
type: 'text'
}, {
name: 'lastname',
type: 'text'
}, {
account: [{
name: 'role',
type: 'text'
}, {
name: 'status',
type: 'text'
}]
}];
$scope.fields = [];
function structuredObj(obj) {
for (var i in obj) {
if (obj[i].type == 'text') {
$scope.fields.push(obj[i]);
} else {
structuredObj(obj[i])
}
}
};
structuredObj(inputs);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<form name="myForm" novalidate>
<div ng-repeat="item in fields" class="form-group">
<input
name="item.name"
type="{{ item.type }}"
placeholder="{{ item.name }}"
ng-model="item.value"
required />
</div>
<button ng-disabled="myForm.$invalid">Submit</button>
</form>
</div>
<div ng-repeat="(key1, value1) in myPersonObj">
<div ng-repeat="(key, value) in value1">
<label>{{key}}</label>
<input type="text" name="" value="{{value}}">
</div>
</div>
var app = angular.module("test",[]);
app.controller("MainCtrl",function($scope){
$scope.inputs = [
{
"firstname" : "Test"
},{
"lastname" : "Test1"
},{
"Account" : [
{"role" : "Test3"},
{"status" : "Test4"},
]
},
{
"Account1" : [
{"role" : "Test3"},
{"status" : "Test4"},
]
},
{
"Account2" : [
{"role" : {
'dim3': {
'dim4':{
'dim5':'cccc'
}
}
}
},
{"status" : "Test4"},
]
}
];
$scope.person = [];
$scope.myPersonObj = [];
/*console.log($scope.keys(inputs));*/
$scope.checkIndex1 = function(arg, myPersonObj)
{
if (angular.isArray(arg) || angular.isObject(arg)) {
angular.forEach(arg, function (value, key) {
console.log(value);
if(angular.isObject(value) || angular.isArray(value))
{
$scope.checkIndex1(value, myPersonObj);
}
else
{
console.log("pushing");
myPersonObj.push(arg);
}
});
}
else
{
console.log("pushing1");
myPersonObj.push(arg);
}
}
$scope.checkIndex1($scope.inputs, $scope.myPersonObj);
console.log("myPersonObj :"+ JSON.stringify($scope.myPersonObj));
console.log($scope.inputs);

Angularjs Ng-repeat with search filter only works on 2nd character keyup

I have implemented basic Angularjs search filter but it only work when I enter 2nd character in input box.
<input type="text" ng-model="search" class="search-input" id="search-input"><div ng-repeat="x in publishList | filter:search"></div>
I have implemented the same and is working, not sure why it is not working for you.
How ever can you try this?
<input type="text" ng-model="search.scheduleName" class="search-input" id="search-input">
I have tried with the code and the array you've given and it works for me.
Could you create a jsfiddle or plnkr example illustrating the problem ?
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ scheduleName : 'Forrest' },
{ scheduleName : 'Gump' },
{ scheduleName : 'saw' },
{ scheduleName : 'xmen' },
{ scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search"/>
<div ng-repeat="item in ctrl.items | filter : ctrl.search">
{{item.scheduleName}}
</div>
</div>
</div>
You can also filter by an object's property in the array by using any one of the two approaches given below.
Specifying the property to filter in the AngularJS built-in filter called filter.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ id: 1, scheduleName : 'Forrest' },
{ id: 2, scheduleName : 'Gump' },
{ id: 3, scheduleName : 'saw' },
{ id: 4, scheduleName : 'xmen' },
{ id: 5, scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search"/>
<div ng-repeat="item in ctrl.items | filter : { scheduleName: ctrl.search }">
{{item.id}}. {{item.scheduleName}}
</div>
</div>
</div>
Specifying an object to be used to filter - this is more dynamic.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{ id: 1, scheduleName : 'Forrest' },
{ id: 2, scheduleName : 'Gump' },
{ id: 3, scheduleName : 'saw' },
{ id: 4, scheduleName : 'xmen' },
{ id: 5, scheduleName : 'troy' }
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<input type="text" ng-model="ctrl.search.scheduleName"/>
<div ng-repeat="item in ctrl.items | filter : ctrl.search">
{{item.id}}. {{item.scheduleName}}
</div>
</div>
</div>

Use variable for the view without modifying the model

I have an object with a list of items X inside, each X has list of Y and each Y has a list of Z.
I would like to hide the span when clicking the button. I can easily do that by adding a property "visible" to each of my object and ng-click="obj.visible = !obj.visible".
But this solution means modifying the object and I don't really want that.
Is there a better solution?
I tried to use track by or a kind of hashmap but without real success.
Should I modify the model and clear it later if I need to save it?
angular.module('myModule', []);
angular.module("myModule")
.controller("DemoCtrl", demoCtrl);
demoCtrl.$inject = ["$scope"];
//demoCtrl
function demoCtrl($scope) {
vm = this;
vm.xObjects = [
{ "xname" : "x1",
"Ys" : [{
"yname" : "y1",
"Zs" : [{ "zname" : "z1" },
{ "zname" : "z2" }]
},
{
"yname" : "y2",
"Zs" : [{ "zname" : "z3" },
{ "zname" : "z4" }]
}]
},
{ "xname" : "x2",
"Ys" : [{
"yname" : "y3",
"Zs" : [{ "zname" : "z5" },
{ "zname" : "z6" }]
},
{
"yname" : "y4",
"Zs" : [{ "zname" : "z7" },
{ "zname" : "z8" }]
}]
}
];
vm.addX = function(){
vm.xObjects.push({ "xname" : "foo", Ys : []});
}
vm.addY = function(x){
x.Ys.push({ "Yname" : "bar", Zs : []});
}
vm.addZ = function(y){
y.Zs.push({ "Zname" : "too"});
}
}
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body data-ng-app="myModule">
<div data-ng-controller="DemoCtrl as demoCtrl" >
<div data-ng-repeat="xobject in demoCtrl.xObjects">
<span data-ng-hide="">xobject.xname = {{xobject.xname}}</span>
<button data-ng-click="">collapse</button>
<div data-ng-repeat="yobject in xobject.Ys">
<span data-ng-hide="">- - -yobject.xname = {{yobject.yname}}</span>
<button data-ng-click="">collapse</button>
<div data-ng-repeat="zobject in yobject.Zs track by $index">
<span data-ng-hide="">- - -{{$index}}- - -zobject.xname = {{zobject.zname}}</span>
<button data-ng-click="">collapse</button>
</div>
- - - - - -<button data-ng-click="demoCtrl.addZ(yobject)">add Z </button>
</div>
- - -<button data-ng-click="demoCtrl.addY(xobject)">add Y </button>
</div>
<button data-ng-click="demoCtrl.addX()">add X </button>
</div>
</body>
</html>
You can do that by creating property named hidden in the controller scope. To hide nested element, you can use arrays.
HTML:
<div ng-controller="DemoCtrl">
<div ng-repeat="x in xs">
<span ng-hide="hidden == $index">{{ x.name }}</span>
<button ng-click="hide($index)">Collapse</button>
<div ng-repeat="y in x.ys">
<span ng-hide="hidden == [x.$index, $index]">{{ y.name }}</span>
<button ng-click="hide([x.$index, $index])">Collapse</button>
<div ng-repeat="z in y.zs">
<span ng-hide="hidden == [x.$index, y.$index, $index]">{{ z.name }}</span>
<button ng-click="hide([x.$index, y.$index, $index])">Collapse</button>
</div>
</div>
</div>
</div>
With this controller:
angular.module("app", [])
.controller("DemoCtrl", function($scope) {
$scope.xs = [...]; // Your data here
$scope.hidden = -1; // Nothing hidden yet
$scope.hide = function(object) {
$scope.hidden = object;
};
});

Resources