Unable to add or remove elements from an array in AngularJS - javascript

Hello: im gettin my feet wet in AngularJS.
I am trying to add and remove elements in an array; however, im unable to accomplish the desired effect.
the foll is the JSON structure:
$scope.masters = [
{
"name": "Wittgenstein",
"thoughts": ["thought 1", "thought 2", "thought 3"]
},
{
"name": "King",
"thoughts": ["thought 1", "thought 2", "thought 3"]
}
];
the foll is the plunker.
Plunker
any input is greatly appreciated. thank you.

As #Mathew suggested, you should introduce the usage of $index as follows:
JS code:
$scope.input = [];
$scope.add = function(i) { // receiving index as param
$scope.masters[i].thoughts.push($scope.input[i]);
$scope.input[i] = '';
};
HTML code:
<div ng-repeat="master in masters">
<h1>{{ master.name }}</h1>
<ul>
<li ng-repeat="thought in master.thoughts">
{{ thought }} <button ng-click="remove($index)">Remove</button>
</li>
</ul>
<input type="text" ng-model="input[$index]">
<button type="submit" ng-click="add($index)">Add</button>
</div>
See this Plunker working example

You need to specify the index of masters. Something like this should work in the remove function:
$scope.masters[masterIndex].thoughts.splice(index, 1);
where masterIndex is the index of the master that you want to remove a thought from

the problem is that you need pass to the add and remove functions the index of the masters. Because you do this:
$scope.masters.thoughts.splice(index, 1);
But masters is an Array, therefore you need to select one object inside that Array, for example
$scope.remove = function(masterIndex, thoughtsIndex) {
$scope.masters[masterIndex].thoughts.splice(thoughtsIndex, 1);
};
For this to work in your HTML you have to use the parent index inside the inner ng-repeat
<div ng-repeat="master in masters">
<h1>{{ master.name }}</h1>
<ul>
<li ng-repeat="thought in master.thoughts">
{{ thought }}
<button ng-click="remove($patent.index, $index)">
Remove
</button>
</li>
</ul>
<input type="text" ng-model="input">
<button type="submit" ng-click="add($index)">Add</button>
</div>
In the Add function you must do the same to recibe the $index of the masters array.

This is an updated version of your plnkr.
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.0" data-semver="1.4.0" src="https://code.angularjs.org/1.4.0/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="demoController">
<div ng-repeat="master in masters track by $index">
<h1>{{ master.name }}</h1>
<ul>
<li ng-repeat="thought in master.thoughts track by $index">
{{ thought }} <button ng-click="remove(master, $index)">Remove</button>
</li>
</ul>
<input type="text" ng-model="input[$index]">
<button type="submit" ng-click="add($index)">Add</button>
</div>
</body>
</html>
Notice how I included the current master as an argument to the remove function. This ensures that the correct master is spliced since JavaScript arrays are passed by reference. Below is the updated angular controller.
var app = angular.module('app', []);
app.controller('demoController', ['$scope', function ($scope) {
$scope.input = [];
$scope.masters = [ {
"name": "Wittgenstein",
"thoughts": ["thought 1", "thought 2", "thought 3"]
}, {
"name": "King",
"thoughts": ["thought 1", "thought 2", "thought 3"]
}];
$scope.add = function(index) {
$scope.masters[index].thoughts.push($scope.input[index]);
$scope.input[index] = '';
};
$scope.remove = function(master, index) {
master.thoughts.splice(index, 1);
};
}]);
The add function seems not to be picking the value from the input model, but then that should be a binding issue, not the function not working as it should.
Working Plunkr
I hope this helps.

Related

Return increment ng repeat in ng repeat with function angularJS

I have a ng-repeat inside another ng-repeat and I need to be able to bring the global count of all records.
I have tried declaring a variable in the view within the ng-repeat so that it adds and does not work.
I currently have the following code.
<body ng-app="app">
<div class="table-responsive" ng-controller="quotesController">
<div ng-repeat="info in datos2 track by $index">
<h2><strong>{{info.name}}</strong></h2>
<div ng-init='count()' ng-repeat="dato in data track by $index">
<span>{{dato.name}}</span>
<br> Position {{id}}
<br />
</div>
</div>
</div>
</body>
Code Angular
$scope.count=function(){
number = number + 1;
$scope.id=number;
}
I need every ng-repeat query to bring me the number position where it is.
Example:
Name 1 ITEM 1 - Position 1
ITEM 2 - Position 2
Name 2 ITEM 1 Position 3
ITEM 2 - Position 4
Name 3 ITEM 1 - Position 5
ITEM 2 - Position 6
http://plnkr.co/edit/I5IWOXGmzbu0UNqn04ha?p=preview
You can return a global counter from a controller and assign it to a scope variable on each ngInit of nested ngRepeat like:
// Code goes here
angular.module('app', [])
.controller('quotesController',
function quotesController($scope) {
$scope.datos2 = [{
"name": "Name 1",
}, {
"name": "Name 2",
}, {
"name": "Name 3",
}
];
$scope.data = [{
"name": "ITEM 1",
}, {
"name": "ITEM 2",
}];
var number = 1;
$scope.count = function(){
return number++;
}
});
<body ng-app="app">
<div class="table-responsive" ng-controller="quotesController">
<div ng-repeat="info in datos2 track by $index">
<h2><strong>{{info.name}}</strong></h2>
<div ng-init='id = count()' ng-repeat="dato in data track by $index">
<span>{{dato.name}}</span>
<br> Position {{id}}
<br />
<br>
</div>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
You should be able to use ngInit for this.
<body ng-app="app">
<div class="table-responsive" ng-controller="quotesController" ng-init="totalCount = 1">
<div ng-repeat="info in datos2 track by $index">
<h2><strong>{{info.name}}</strong></h2>
<div ng-repeat="dato in data track by $index" ng-init="position = totalCount++">
<span>{{dato.name}}</span>
<br> Position {{position}}
<br />
</div>
</div>
</div>
</body>
You can use {{($parent.$index*data.length)+($index+1)}}
<div ng-repeat="info in datos2 track by $index">
<h2><strong>{{info.name}}</strong></h2>
<div ng-init='count()' ng-repeat="dato in data track by $index">
<span>{{dato.name}}</span>
<br> Position {{($parent.$index*data.length)+($index+1)}}
<br />
<br>
</div>
</div>
http://plnkr.co/edit/0mcgZfxmL5PBwSDp0hoo?p=preview

How to repeat an angular element starting on index 1?

I want my ng-repeat to start after position 1, so I did this, but it doesn't work. Should I crop the array before painting it or is there a native way to do this?
var myapp = angular.module("myapp", [])
.controller("MainController", control_fun);
function control_fun() {
this.items = ["position 0", "position 1", "position 2", "position 3"];
};
<div ng-app="myapp">
<div ng-controller="MainController as ctrl">
<div ng-repeat="item in ctrl.items | filter: item > 1">{{item}}</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
If your are running angular >= 1.4.0, you can use limitTo : limit: begin filter
<div ng-repeat="item in ctrl.items | limitTo : ctrl.items.length : 1}}</div>
Check this plnkr
You can slice the array and use rest to iterate
<div ng-repeat="item in ctrl.items.slice(1) track by $index">
Demo:
var myapp = angular.module("myapp",[])
.controller("MainController", control_fun);
function control_fun(){
this.items = ["position 0", "position 1", "position 2", "position 3"];
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<div ng-controller="MainController as ctrl">
<div ng-repeat="item in ctrl.items.slice(1) track by $index">{{item}}</div>
</div>
</div>

angularjs tutorial code debug

im learning angularjs thru an Apress book and I've come across some code that doesnt work, ive tried to debug but my console isnt giving me any errors or anything. Maybe some experts can guide me thru whats wrong, thanks.
customFilters.js file
// Creating a custom filter
// arguments for the filter method is unique and a factory function that returns a filter function that does the actaul work
angular.module('customFilters',[]).filter('unique', function() {
return function(data, propertyname) {
if (angular.isArray(data) && angular.isString(propertyname)) {
var results = [];
var keys = {};
for (var i = 0; i < data.length; i++) {
var val = data[i][propertyname];
if (angular.isUndefined(keys[val])) {
keys[val] = true;
results.push(val);
}
}
return results;
} else {
return data;
}
}
});
sportsStore.js file
//declaring a dependency called customFilters that contains a unqiue filter
angular.module('sportsStore',['customFilters']);
// calling the angular.module method passing in sportsStore located in app.html
angular.module('sportsStore').controller('sportsStoreCtrl', function($scope) {
$scope.data = {
products: [
{name: "Product 1", description:"A product", category:"Category #1", price: 100},
{name: "Product 2", description:"A product", category:"Category #1", price: 110},
{name: "Product 3", description:"A product", category:"Category #2", price: 210},
{name: "Product 4", description:"A product", category:"Category #3", price: 202}
]
};
});
my productListControllers.js file
angular.module('sportsStore').controller('productListCtrl', function($scope,$filter){
var selectedCategory = null;
$scope.selectedCategory = function(newCategory) {
selectedCategory = newCategory;
};
$scope.categoryFilterFn = function(product) {
return selectedCategory == null || product.category == selectedCategory;
};
});
app.html file
<!DOCTYPE html>
<!-- We are defining the sportStore module here in the html tag-->
<html ng-app="sportsStore">
<head>
<title>Sports Store</title>
<link href="bootstrap.min.css" rel="stylesheet" />
<link href="bootstrap-theme.min.css" rel="stylesheet" />
</head>
<!-- Applying ng-controller to the body tagg -->
<body ng-controller="sportsStoreCtrl">
<div class="navbar navbar-inverse">
<a class="navbar-brand" href="#">Sports Store</a>
</div>
<div class="panel panel-default row" ng-controller="productListCtrl">
<div class="col-xs-3">
<a class="btn btn-block btn-default btn-lg" ng-click="selectCategory()">Home</a>
<!-- generating the navigation elements here -->
<a class="btn btn-block btn-default btn-lg" ng-repeat="item in data.products |orderBy:'category'| unique:'category'" ng-click="selectCategory(item)">{{item}}</a>
</div>
<div class="col-xs-8">
<!-- ng-repeat generates elements for each object in an array -->
<!-- we also create a local variable called item -->
<div class="well" ng-repeat="item in data.products | filter:categoryFilterFn">
<h3>
<strong>{{item.name}}</strong>
<span class="pull-right label label-primary">{{item.price | currency}}</span>
</h3>
<span class="lead">{{item.description}}</span>
</div>
</div>
</div>
<script src="angular.js"></script>
<script src="controllers/sportsStore.js"></script>
<script src="filters/customFilters.js"></script>
<script src="controllers/productListControllers.js"></script>
</body>
</html>
You have a typo in your html file. The function is selectedCategory not selectCategory.
There is a typo, the template says selectCategory and the controller says selectedCategory

AngularJs filtering data In the other Controller

I am using two controllers and a factory service to get the data from it. I want to filter the data in the second controller by input 'ng-model'. So i have written input ng-model in both the controllers (check index.html). Its working if i tried to enter the input data in the second controller input field, but its not working if i try filtering from first controller input ng-app.
index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<script src="scripts/controller.js"></script>
</head>
<body ng-app="app" ng-controller="appCtrl">
<div style="float: left; width: 300px;">
<div ng-controller="checkBoxModuleCtrl">
<ul>
<li ng-repeat="item in chkBoxList" style="list-style: none;">
<input type="checkBox" value="{{item}}" ng-click="checkBoxClickHandler($index, $event)"> {{item}}
</li>
</ul>
<input type="text" ng-model="myText" />
</div>
</div>
<!--<input type="button" ng-click="checkBoxClickHandler()" value="Click Me!"> </input>-->
<div style="float: left; width: 400px; height: 600px; overflow-y: scroll;" >
<div>
<div ng-controller="panelCtrl">
<input type="text" ng-model="myText" />
<ul>
<li ng-repeat="panelItem in panelData|filter:myText" style="list-style: none;">
<div>
<b>Title </b/>: {{panelItem.name }}<br/>
<b>Channel-Type </b>: {{panelItem.type }}<br/>
<b>description </b>: {{panelItem.description }}
</div>
<hr weight="5" />
</li>
</ul>
</div>
</div>
</div>
</body>
</html>
controller.js
var app = angular.module("app", ["checkBoxserviceModule"]);
app.controller('appCtrl', function($scope){
});
app.controller('checkBoxModuleCtrl', function($scope, externals){
$scope.chkBoxList = [];
$scope.init = function(){
$scope.chkBoxList = externals.getCheckBoxList()
};
$scope.init();
$scope.checkBoxClickHandler = function(itemIndex, event){
alert(event.currentTarget.value + "will be handling click listener for check box" + itemIndex)
}
});
app.controller("panelCtrl", function($scope, externals){
$scope.init = function(){
$scope.panelData = externals.getPanelData();
};
$scope.init();
$scope.customFilter = function(panelItem){
return panelItem.toUpperCase;
}
});
var checkBoxserviceModule = angular.module("checkBoxserviceModule", []);
checkBoxserviceModule.factory("externals", function(){
return{
getCheckBoxList : function(){
return [ "sports", "movies", "entertainment", "news" ]
},
getPanelData : function(){
//alert("in services")
return [
{
"name":"cinmax",
"type": "movies",
"description":"Some Tesxt"
},
{
"name":"setmax",
"type": "sports",
"description":"Some Tesxt"
},
{
"name":"mtv",
"type": "entertainment",
"description":"Some Tesxt"
},
{
"name":"ibn news",
"type": "news",
"description":"Some Tesxt"
}
];
}
};
});
Controllers use prototypical inheritance to share scope. So, you need to make sure the object you want inherited is an actual object in order for the reference to stay binded. If try to share a primitive from the scope, they will not be binded correctly and each controller will end up making it's own copy.
This might inherit correctly initially, but the binding will disconnect as soon as you change the value of the child's scope.number.
-ParentController
-scope.number = 4
-ChildController
-scope.number //will not stay binded to parent's scope
This on the otherhand, if you create an object on the scope, will inherit a reference to the object, and will stay binded in the child controller.
-ParentController
-scope.myObject.number = 4
-ChildController
-scope.myObject.number //will stay binded to parent's scope
Here is a better explanation: Why don't the AngularJS docs use a dot in the model directive?

Binding a single angular expression out of a json-file

I am pretty new to angularJS, and obviously there are some simple things that i do not yet understand. What i want to do is the following:
I've got a de-DE.json (that e.g. has several language-keys for a planned multi-language site) that looks somewhat like this
{
"index": {
"headline": "The title of that view",
"tabmenu": [
{
"id": "home",
"class": "active in",
"title":"Title No. 1",
"description":"Some description"
},
{
"id": "profile",
"class": "",
"title":"Title No. 2",
"banner":"WallBanner.jpg",
"description":"Some description"
},
{
"id": "messages",
"class": "",
"title":"Title No. 3",
"description":"Some description"
},
{
"id": "settings",
"class": "",
"title":"Title No. 4",
"description":"Some description"
}
]
},
"media": {
...
}
}
Next have a look at my index.html that looks like:
<html ng-app id="ng-app">
<head>
<title>Title of the Site</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.min.css">
</head>
<body ng-controller="languageKey">
<div class="container" ng-model="language.index">
<h1>{{ headline }}</h1>
<div class="row">
<div class="col-lg-12">
<ul class="nav nav-tabs" id="myTab">
<li class="active">Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
<li>Tab4</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade {{ lg.class }}" id="{{ lg.id }}" ng-repeat="lg in language.index.tabmenu">
<h3>{{ lg.title }}</h3>
<p>{{ lg.description }}</p>
</div>
</div>
</div>
</div>
</div>
<script src="../assets/jquery/jquery.js"></script>
<script src="../assets/bootstrap/js/bootstrap.min.js"></script>
<script src="../assets/angularjs/angular.min.js"></script>
<script>
$(function () {
$('#myTab a:first').tab('show')
})
function languageKey($scope, $http)
{
$http({method: 'POST', url: 'de-DE.json'}).success(function(data)
{
$scope.language = data; //response Data
});
}
</script>
</body>
</html>
So thanks to some google-knownledge the part with the <div ng-repeat="lg in language.index.tabmenu"> works fine.
But much more common are language-keys that are just used once, without repeating html structure like in the above
<h1>{{ headline }}</h1>
(I've also tried <h1 ng-bind="{headline}"
So is there a leightweight way to just call those expressions?
Obviously it doesn't work if i try ng-model="language.index" in that case.
You just have to set your JSON object in your $scope element inside your controller, and you can use it in the view:
$scope.myJSON = {...};
In HTML
<h1>{{myJSON.index.headline }}</h1>
By the way, if you're implementing a multi-language application take a look at angular-translate.
If this works
<div ng-repeat="lg in language.index.tabmenu">
then as long as you load the parsed JSON object into the $scope the same way, this should output the headline:
<h1>{{ language.index.headline }}</h1>
The docs suggest that ng-model only works with inputs:
ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope

Categories