Angular. Push array in array - angularjs

I try to do TODO list using Angular.js
I have function addTask, but it dosen't work. I try to give it project and than get array of tasks. In Chrome I see this mistake "Cannot read property 'tasks' of undefined"
This is my app.js
var app = angular.module('toDoList', ['ngDialog']);
app.controller('MainCtrl', [
'$scope',
'$rootScope',
'ngDialog',
function($scope, $rootScope, ngDialog){
$scope.test = 'Hello world!';
$scope.projects = [
{id: '1', title: 'For Home', tasks: [ {title: 'task 1', done:false }, {title: 'task 2', done: false }]},
{id: '2', title: 'For Work', tasks: [ {title: 'task 1', done:false }, {title: 'task 2', done: false }]}
];
$scope.addProject = function(){
if(!$scope.title || $scope.title === '') { return; }
$scope.projects.push({
title: $scope.title
});
};
$scope.addTask = function(project){
$scope.project.tasks.push({
title: $scope.tasktitle, done: false
});
}]);
This is my html code
<body ng-app="toDoList" ng-controller="MainCtrl">
<div class="project" ng-repeat="project in projects">
<span class="title">{{project.title}}</span>
<form name="frm" ng-submit="addTask(project)">
<input
type="text"
class="form-control"
placeholder="Start to type task"
ng-model="tasktitle">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">Add Task</button>
</span>
</form>
<ul class="todo-list">
<li ng-repeat="task in project.tasks">
<input type="checkbox" ng-model="task.done">
<span ng-class="{done:task.done}">{{task.title}}</span>
</li>
</ul>
</div>
</body>
How can I push my data about task?
This is doesn't work:
$scope.addTask = function(project){
$scope.project.tasks.push({
title: $scope.tasktitle, done: false
});
};

First and foremost, you're missing an 's' in $scope.project.tasks.push. It should be projects, so as to match up with the scope variable.
Second, you're not actually choosing a project to push to. $scope.projects is an Array. You would need to choose an index to push to. Here's what I think you're going for:
HTML
<form name="frm" ng-submit="addTask(project.id, tasktitle)">
Javascript
$scope.addTask = function(id, task){
$scope.projects[id].tasks.push({
title: task
, done: false
});
};
EDIT: Working codepen at: codepen.io/Pangolin-/pen/YPVwye – Pangolin

I could fix this, but i don't know is it right?
HTML
<form name="frm" ng-submit="addTask(project.tasks, tasktitle)" class="input-group">
Javascript
$scope.addTask = function(project, value){
project.push({
title: value
});

Related

Angular radio buttons - undefined value on check

I have radiobuttons in Angular 1 like this http://jsfiddle.net/md3coyzn/1/ and I need to change value to true / false when radio button is clicked, but I am still getting undefined value, and dont know why
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
<div ng-repeat="radio in radioContent">
<input type="radio" name="group" ng-model="radio.checked">{{radio.txt}} ---> {{radio.checked}}
</div>
as ng-repeat create its own scope. so you have to access by using $parent
HTML
<div ng-repeat="radio in radioContent track by $index">
<input type="radio" name="group[$index]" ng-model="$parent.selectedRadio" ng-change="$parent.radioChecked()" ng-value="radio" >{{radio.txt}}
</div>
JS
.controller('ExampleCtrl', ['$scope', function ($scope) {
$scope.selectedRadio;
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
$scope.radioChecked = function () {
console.log('selectedRadio', $scope.selectedRadio);
$scope.selectedRadio.checked = !$scope.selectedRadio.checked
}
}]);
please check the working Fiddle
hope it helps you.
An ng-click method to toggle the value of the radio buttons.
Note that value attribute of the button conflicts with the ng-model attribute so had to remove the later one.
angular.module('ExampleApp', [])
.controller('ExampleCtrl', ['$scope', function ($scope) {
console.clear();
$scope.radioContent = [
{txt: 'One', checked: true},
{txt: 'Two', checked: false}
];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp" ng-controller="ExampleCtrl">
<div ng-repeat="radio in radioContent">
<input type="radio" name="group" value="{{radio.checked}}" ng-click="radio.checked = !radio.checked">{{radio.txt}} ---> {{radio.checked}}
</div>
</div>

Unable to show content of array as checkboxes using ng-repeat

I have the following in my controller:
var myApp = angular.module("myApp", []);
myApp.controller("TestCtrl", ['$scope', function($scope) {
$scope.rows = [
'Facebook',
'Twitter',
'Pinterest',
'Instagram',
'Tumblr',
'Google'
];
}]);
and I'm trying to show the content like this
<div class="container">
<div ng-app="myApp">
<div ng-controller="TestCtrl">
<label ng-repeat="row in rows">
<input type="checkbox" ng-checked="row.selected" ng-model="row.selected" />{{row}}</label>
</div>
</div>
right now the items show, but I can't check the checkboxes,
check this Plunker
In order to have your checkbox checkable, you need to pass a valid ng-model there. In your case, row.selected is invalid since every row is a string and not object.
You can have your $scope.rows array like this instead:
$scope.rows = [{
name: 'Facebook',
selected: false
}, {
name: 'Twitter',
selected: false
}, {
name: 'Pinterest',
selected: false
}, {
name: 'Instagram',
selected: false
}, {
name: 'Tumblr',
selected: false
}];
Here's a forked plunker which has checkboxes checkable

Angular: How to $broadcast from Factory?

I have a list of items and I need to get a message (saying Item added!) in the navbar whenever a new item is added.
The function addItem() (ng-click on the Add Item button) is in the ItemFactory and from there I seem to not be able to broadcast it.
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
</head>
<body ng-app="MyApp" ng-controller="MainCtrl">
<div>{{ text }}
<nav class="navbar navbar-inverse" ng-controller="NavCtrl">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">List of items | {{ alertItemAdded }}</a>
</div>
<form class="navbar-form navbar-right" role="search">
<div class="form-group">
<input type="text" class="form-control" ng-model="newItem" placeholder="Add an item">
</div>
<button type="submit" class="btn btn-primary" ng-click="addItem(newItem)">Add Item</button>
</form>
</div>
</nav>
<div class="container" ng-controller="ContentCtrl">
<div class="row">
<div class="col-xs-12">
<form class="form-inline">
<div class="form-group">
<input type="text" class="form-control" ng-model="newItem" placeholder="Add an item">
</div>
<button type="submit" class="btn btn-primary" ng-click="addItem(newItem)">Add Item</button>
</form>
<br />
<br />
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div ng-repeat="item in items">
<form class="form-inline">
<div class="form-group">
<div>{{ item }}</div>
</div>
<button type="button" class="btn btn-default btn-s" ng-click="removeItem($index)">Remove Item</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
angular.module('MyApp',[]);
angular.module('MyApp').controller('MainCtrl', function($scope, ItemFactory){
$scope.text = "Text from the Main Controller";
$scope.addItem = function(newItem){
ItemFactory.addItem(newItem);
}
});
angular.module('MyApp').controller('NavCtrl', function($scope){
// $on
$scope.$on('itemAdded', function(event, data){
$scope.alertItemAdded = data;
});
});
angular.module('MyApp').controller('ContentCtrl', function($scope, ItemFactory){
$scope.items = ItemFactory.getItem();
$scope.removeItem = function($index){
ItemFactory.removeItem($index);
}
});
angular.module('MyApp').factory('ItemFactory', function(){
var items = [
'Item 1',
'Item 2',
'Item 3'
];
return {
getItem : function() {
return items;
},
addItem : function(item){
items.push(item);
// $broadcast
$scope.$broadcast('itemAdded', 'Item added!');
},
removeItem : function($index){
items.splice($index, 1);
}
};
});
You can inject $rootScope into your factory and use $broadcast from there.
angular.module('MyApp').factory('ItemFactory', ["$rootScope", function($rootScope){
var items = [
'Item 1',
'Item 2',
'Item 3'
];
return {
getItem : function() {
return items;
},
addItem : function(item){
items.push(item);
// $broadcast
$rootScope.$broadcast('itemAdded', 'Item added!');
},
removeItem : function($index){
items.splice($index, 1);
}
};
}]);
Here is a clean solution for you.
See it working in this plunker
Let me explain how all of this works.
Your message looks like this :
<span ng-if="alertItemAdded.recentAdd">Item added !</span>
It will show only when "alterITemAdded.recenAdd" is true. You'll use this to make the message disapear if you need.
You factory look like this now :
angular.module('MyApp').service('ItemService', function(){
var service = {};
//I'll always wrap my data in a sub object.
service.notification = {};
service.notification.recentAdd=false;
service.items = {};
service.items.list = [
'Item 1',
'Item 2',
'Item 3'
];
service.items.addItem = function(item){
service.items.list.push(item);
service.notification.recentAdd=true;
console.log(service);
}
service.items.removeItem = function($index){
service.items.list.splice($index, 1);
}
return service;
});
I'm using service instead of factory. But there is almost no difference, it's just a matter of taste.
Here is your controllers
angular.module('MyApp').controller('MainCtrl', function($scope, ItemService){
$scope.text = "Text from the Main Controller";
});
angular.module('MyApp').controller('NavCtrl', function($scope, ItemService){
//IMPORTANT POINT : I bind it the sub object. Not to the value. To access the value i'll use $scope.alterItemAdded.recentAdd
$scope.alertItemAdded = ItemService.notification;
//I don't have to redeclare the function. I just bind it to the service function.
$scope.addItem = ItemService.items.addItem;
});
angular.module('MyApp').controller('ContentCtrl', function($scope, ItemService){
$scope.items = ItemService.items.list;
$scope.addItem = ItemService.items.addItem;
$scope.removeItem = function($index){
ItemService.items.removeItem($index);
}
});
Important point :
I always bind my vars to a sub object. Why ? In fact if i did
$scope.alertItemAdded = ItemService.notifications.recentAdd
When i do something like this in my service
service.notifications.recentAdd = true;
It will create a new variable and put the reference into service.notifications.recentAdd. The $scope.alertItemAdded was bind to the previous reference and wont see the update.
Doing this :
$scope.alterItemAdded = ItemService.notification
And using the value in the ng-if clause or anything else. I prevent the reference link to break. If i do in the service
service.notification.recentAdd = true
I'll create a new var with a new reference for "recentAdd" but i keep the same reference for "notification". The binding in the controller will be keep and the value recentAdd will be updated in the view.
If you have more question feel free to ask.
You not injected $scope to factory, and you cant actually, use $rootScope instead
$broadcast goes from top to bottom so you should use $rootScope to perform a $broadcast to all $scope elements below it.
Inject $rootScope in your factory
$rootScope.$broadcast('itemAdded, 'Item added!')

angularjs - ng-show not working with ng-repeat

I have a variable set to true in ng-click but the div underneath is not displaying. I've followed this post but it looks like it doesnt work in maybe ng-repeat? Here's the plunker: http://plnkr.co/edit/90G1KAx9Fmf2SgRs5gYK?p=preview
angular.module('myAppApp', [])
.controller('MainCtrl', function ($scope) {
$scope.notes = [{
id: 1,
label: 'First Note',
done: false,
someRandom: 31431
}, {
id: 2,
label: 'Second Note',
done: false
}, {
id: 3,
label: 'Finished Third Note',
done: true
}];
$scope.reach= function (id) {
//the assignment below works
//$scope.flag = true;
alert("hello there");
};
});
<div ng-app="myAppApp">
<div ng-controller="MainCtrl">
<div ng-repeat="note in notes">
{{note.id}} - {{note.label}} -
click me
</div>
<div class="row" id="" ng-show="flag">I'm Here</div>
</div>
</div>
It should be ng-click="$parent.flag = true;reach(111);"
click me
Outside ng-repeat
You question is unclear, you could use ng-repeat inside ng-repeat, by maintaining variable in ng-repeat parent scope. and access parent scope using $parent. annotation inside ng-repeat
<div ng-repeat="note in notes">
{{note.id}} - {{note.label}} -
click me
<div class="row" id="" ng-show="$parent.selected == note.id">I'm Here</div>
</div>
</div>
Inside ng-repeat
I would advise you to use ng-init
<div ng-repeat="note in notes" ng-init="parent=$parent">
and after that
click me
Please see demo below
angular.module('myAppApp', [])
.controller('MainCtrl', function($scope) {
$scope.notes = [{
id: 1,
label: 'First Note',
done: false,
someRandom: 31431
}, {
id: 2,
label: 'Second Note',
done: false
}, {
id: 3,
label: 'Finished Third Note',
done: true
}];
$scope.reach = function(id) {
//$scope.flag = true;
alert("hello there");
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
<div ng-app="myAppApp">
<div ng-controller="MainCtrl">
<div ng-repeat="note in notes" ng-init="parent=$parent">
{{note.id}} - {{note.label}} -
click me
</div>
<div class="row" id="" ng-show="flag">I'm Here</div>
</div>
</div>
</body>

How to get multiple selected check box values

How to get multiple selected check box values in Angular.js and insert into database separated with a comma (,) ?
You can use ng-repeat + ng-model over an array of options.
DEMO http://plnkr.co/edit/KcUshc74FZL1npZsKbEO?p=preview
html
<body ng-controller="MainCtrl">
<div class="container">
<h1>Options</h1>
<div>
<div class="form-group" ng-repeat="option in options">
<label>{{option.name}}</label>
<input type="checkbox" ng-model="option.value">
</div>
</div>
<hr>
<button class="btn btn-primary" ng-click="save()">save to database</button>
</div>
</body>
js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.options = [{
name: 'java',
value: true,
}, {
name: 'c#',
value: false
}, {
name: 'angular',
value: true
}, {
name: 'r',
value: false
}, {
name: 'python',
value: true
}, {
name: 'c++',
value: true
}];
$scope.save = function() {
var optionsCSV = '';
$scope.options.forEach(function(option) {
if (option.value) {
// If this is not the first item
if (optionsCSV) {
optionsCSV += ','
}
optionsCSV += option.name;
}
})
// Save the csv to your db (replace alert with your code)
alert(optionsCSV);
};
});

Resources