I have a list of subjects coming from the controller which are populating checkboxes. Some of the checkboxes are checked intially, I have a edit button. When I click the update button, an alert should pop up, and the alert should show the checked subject's ids. But the problem is, when I load the page , and then if I click the update button, the initially checked subject ids do not pass to the controller. It works only if I uncheck those check boxes and recheck them. Here is my code snippet.
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script>
var myApp2=angular.module("myModule2",[]);
myApp2.controller("controller2",function($scope){
$scope.message="test";
$scope.Subjects=[
{SubjectId:1,SubjectName:"Bangla"},
{SubjectId:2,SubjectName:"English"},
{SubjectId:3,SubjectName:"Math"},
{SubjectId:4,SubjectName:"Science"},
{SubjectId:5,SubjectName:"BGS"},
{SubjectId:6,SubjectName:"Religious"},
];
$scope.SubjectIds=[2,5];
$scope.subjectModel = {};
$scope.edit = function () {
var checkedSubjects = [];
for (var k in $scope.subjectModel) {
if ($scope.subjectModel.hasOwnProperty(k) && $scope.subjectModel[k]) {
checkedSubjects.push(k);
}
}
//do your stuff with the ids in `checkedBooks`
alert(checkedSubjects);
}
});
</script>
</head>
<body ng-app="myModule2" ng-controller="controller2">
Subjects:
<div ng-repeat="subj in Subjects">
<input type="checkbox" ng-model="subjectModel[subj.SubjectId]" ng-checked="SubjectIds.indexOf(subj.SubjectId)!=-1"/>{{subj.SubjectName}}
</div>
<div>
<input type="button" class="btn btn-warning" value="Update" id="updt" ng-click="edit()"/>
</div>
</body>
</html>
The problem was improper use of ng-model.
First: To work ng-model properly you have to create proper instances of the variables which is created by the code and sets its value true or false depends on whether the ids exists in the variable $scope.Subjects[i]:
$scope.subjectModel = [];
for(var i = 0; i < $scope.Subjects.length; i++) {
$scope.subjectModel[$scope.Subjects[i].SubjectId]
= $scope.SubjectIds.indexOf($scope.Subjects[i].SubjectId) > -1 ? true:false;
}
Second: the edit function is changed whether the checkbox is checked or not by using the following modified code:
for (var k = 0; k < $scope.subjectModel.length; k++) {
if ($scope.subjectModel[k]) {
checkedSubjects.push(k);
}
}
Third: To load data dynamically, you need to call $scope.updateChkBox(); after $scope.Subjects = pl.data; The modified loadSubjects function given below:
function loadSubjects() {
var promiseGet = crudService.getSubjects();
promiseGet.then(function (pl) {
$scope.Subjects = pl.data;
$scope.updateChkBox();
},
function (errorPl) {
$log.error('failure loading Subjects', errorPl);
});
}
Please check the final working code snippet:
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script>
var myApp2=angular.module("myModule2",[]);
myApp2.controller("controller2",function($scope){
$scope.message="test";
$scope.Subjects=[
{SubjectId:1,SubjectName:"Bangla"},
{SubjectId:2,SubjectName:"English"},
{SubjectId:3,SubjectName:"Math"},
{SubjectId:4,SubjectName:"Science"},
{SubjectId:5,SubjectName:"BGS"},
{SubjectId:6,SubjectName:"Religious"},
];
$scope.SubjectIds=[2,5];
$scope.subjectModel = [];
$scope.updateChkBox = function (){
for(var i = 0; i < $scope.Subjects.length; i++) {
$scope.subjectModel[$scope.Subjects[i].SubjectId]
= $scope.SubjectIds.indexOf($scope.Subjects[i].SubjectId) > -1 ? true:false;
}
}
$scope.updateChkBox();
function loadSubjects() {
var promiseGet = crudService.getSubjects();
promiseGet.then(function (pl) {
$scope.Subjects = pl.data;
$scope.updateChkBox();
},
function (errorPl) {
$log.error('failure loading Subjects', errorPl);
});
}
$scope.edit = function () {
var checkedSubjects = [];
for (var k = 0; k < $scope.subjectModel.length; k++) {
if ($scope.subjectModel[k]) {
checkedSubjects.push(k);
}
}
//do your stuff with the ids in `checkedBooks`
alert(checkedSubjects);
}
});
</script>
</head>
<body ng-app="myModule2" ng-controller="controller2">
Subjects:
<div ng-repeat="subj in Subjects">
<input type="checkbox" ng-model="subjectModel[subj.SubjectId]" ng-checked="SubjectIds.indexOf(subj.SubjectId)!=-1"/>{{subj.SubjectName}}
</div>
<div>
<input type="button" class="btn btn-warning" value="Update" id="updt" ng-click="edit()"/>
</div>
</body>
</html>
Related
I need some help with this code, i'm storing "activities" and removing it.
For now it's storing but not removing. (I just need a simple solution to this code).
Angular.js
angular
.module("TodoList",["LocalStorageModule"])
.factory("TodoService", function(localStorageService){
var todoService = {};
todoService.key = "angular-todolist";
if(localStorageService.get(todoService.key)){
todoService.activities = localStorageService.get(todoService.key);
} else {
todoService.activities = [];
}
todoService.add = function(newActv){
todoService.activities.push(newActv);
todoService.updaLocalStorage();
};
todoService.updaLocalStorage = function(){
localStorageService.set(todoService.key, todoService.activities);
};
todoService.clean = function(){
todoService.activities = [];
todoService.updaLocalStorage();
};
todoService.getAll = function(){
return todoService.activities;
};
toDoService.removeItem = function (item) { **Creating function for remove**
toDoService.activities = toDoService.activities.filter(function (activity) {
return activity !== item;
});
toDoService.updateLocalStorage();
return toDoService.getAll();
};
return toDoService;
})
.controller("TodoListCtrl", function($scope, todoService){
$scope.todo = todoService.getAll();
$scope.newActv = {};
$scope.addActv = function(){
todoService.add($scope.newActv);
$scope.newActv = {};
}
$scope.removeActv = function (item) { **Scope for remove**
$scope.todo = ToDoService.removeItem(item);
}
$scope.clean = function(){
todoService.clean();
}
});
Html
<!DOCTYPE html>
<html ng-app = "TodoList">
<head>
<meta charset="utf-8">
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<script src = "todoctrl.js"></script>
<script src = "angular-local-storage.min.js"></script>
</head>
<body ng-controller = "TodoListCtrl">
<ul>
<li ng-repeat = "actividad in todo">
{{actividad.descripcion}} -
{{actividad.fecha | date: 'short'}} -
x **Where is removing**
</li>
</ul>
<form ng-submit = "addActv()">
<input type="text" ng-model = "newActv.descripcion">
<input type="datetime-local" ng-model = "newActv.fecha">
<input type="submit" value = "Guardar">
</form>
<button ng-click = "clean()">Limpiar</button>
</body>
</html>
update your ToDoService.removeItem(item);function. if you want to remove an item from activity you use array.splice(item) to remove an item from an array. you want to remove an item ToDoService.removeItem(item); function but your function is not doing this. it is returning a value that is either true or false. change your function body.
i have a problem while im trying to share a data between two controllers.
Here is my code :
<html>
<head>
<title>My Angular App</title>
</head>
<body ng-app="MyTest">
<div ng-controller="ViewController as vmView">
<ul>
<li ng-repeat="singleItem in vmView.allData">
{{ singleItem }}
</li>
</ul>
{{ vmView.checkItOut }}
<input type="button" ng-click="vmView.justClick()" />
</div>
<div ng-controller="AddController as vmAdd">
<form ng-submit="vmAdd.saveChanges()">
<input type="text" ng-model="vmAdd.inputText" />
<input type="submit" />
</form>
</div>
<script src="angular.js"></script>
<script src="app.js"></script>
<script type="application/javascript">
angular.module('MyTest')
.factory('shareDataFactory', function($http, $q) {
var data = {};
data.list = $q.defer();
data.getAllData = function() {
$http.get('http://www.w3schools.com/angular/customers.php')
.then(function(response) {
data.list = $q.resolve(response.data.records);
});
return data.list.promise;
};
data.addData = function(newData) {
data.list.push(newData);
};
return data;
});
angular.module('MyTest')
.controller('ViewController', function ViewController(shareDataFactory) {
var vm = this;
vm.allData = shareDataFactory.getAllData();
vm.checkItOut = "Just checking ..";
vm.justClick = function() {
console.log(vm.allData);
}
});
angular.module('MyTest')
.controller('AddController', function AddController(shareDataFactory) {
var vm = this;
vm.inputText = "Hello";
vm.saveChanges = function() {
shareDataFactory.addData(vm.inputText);
// Clear the data
vm.inputText = "";
};
});
</script>
</body>
</html>
vm.allData its just not updating affter the request come back from the server.
i tried to solve this for a long time but without success.
thanks you everyone and have a lovely week,
rotem
Your code doesn't make much sense:
data.list = $q.defer();
So, data.list is a deferred object. But later
data.list = $q.resolve(response.data.records);
Ah, it's not a deferred anymore: it's being replaced by a resolved promise, unrelated to the promise returned by getAllData(). But later
data.list.push(newData);
Ah, that code thinks it's an array, and not a promise not a deferred.
That can't be right. If you want to be able to push, it must be an array. If you want to populate the array when the http promise is resolved, then push to this aray
It's also unclear what the service should do: it gets data from an HTTP service, but doesn't send the new values to that HTTP service. So, every time you'll call getAllData(), you'll lose the added values.
Anyway:
var list = [];
var getAllData = function() {
$http.get('http://www.w3schools.com/angular/customers.php')
.then(function(response) {
// clear the array
list.splice(0, list.length);
// copy every record to the array
response.data.records.forEach(function(record) {
list.push(record);
});
});
return list;
};
var addData = function(newData) {
list.push(newData);
};
return {
getAllData: getAllData,
addData: addData
};
Here you can find a working version of your code.
When data is loaded, you are replacing the bound list with a new one, so changes aren't getting reflected anymore.
Html
<div ng-controller="ViewController as vmView">
<ul>
<li ng-repeat="singleItem in vmView.allData">
{{ singleItem }}
</li>
</ul>
{{ vmView.checkItOut }}
<input type="button" ng-click="vmView.justClick()" />
</div>
<div ng-controller="AddController as vmAdd">
<form ng-submit="vmAdd.saveChanges()">
<input type="text" ng-model="vmAdd.inputText" />
<input type="submit" />
</form>
</div>
</body>
Javascript
var module = angular.module('MyTest', []);
module.service('shareDataFactory', function($http, $q) {
var data = {
list: []
};
$http.get('http://www.w3schools.com/angular/customers.php')
.then(function(response) {
Array.prototype.push.apply(data.list, response.data.records);
});
return {
getData: function() {
return data;
},
addData: function(newData) {
data.list.push(newData);
}
};
});
module.controller('ViewController', function ViewController($scope, shareDataFactory) {
$scope.allData = shareDataFactory.getData().list;
$scope.checkItOut = "Just checking ..";
$scope.justClick = function() {
console.log($scope.allData);
}
});
module.controller('AddController', function AddController($scope, shareDataFactory) {
$scope.inputText = "Hello";
$scope.saveChanges = function() {
shareDataFactory.addData($scope.inputText);
// Clear the data
$scope.inputText = "";
};
});
var myApp = angular.module("myApp", ["firebase"]);
var nick = prompt("Anna nimesi");
myApp.controller("MyController", ["$scope", "$firebaseArray",
function($scope, $firebaseArray) {
var msgref = new Firebase("https://(myapp).firebaseio.com/messages");
var usrref = new Firebase("https://(myapp).firebaseio.com/users");
$scope.messages = $firebaseArray(msgref);
$scope.users = $firebaseArray(usrref);
console.log($scope.users);
console.log($scope.messages);
var taken = false;
angular.forEach($scope.users, function(value, key) {
console.log(value, key);
if (value.username == nick) {
taken = true;
}
// put your code here
});
if (taken == false) {
$scope.users.$add({
username: nick
});
};
$scope.addMessage = function(e) {
if (e.keyCode == 13 && $scope.msg) {
var name = nick || "anynomous";
$scope.messages.$add({
from: name,
body: $scope.msg
});
$scope.msg = "";
}
}
}
])
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
<title>title</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://cdn.firebase.com/js/client/2.2.4/firebase.js"></script>
<script src="https://cdn.firebase.com/libs/angularfire/1.1.1/angularfire.min.js"></script>
</head>
<body ng-controller="MyController">
<div class="example-chat l-demo-container">
<ul id="example-messages" class="example-chat-messages">
<li ng-repeat="msg in messages">
<strong class="example-chat-username">{{msg.from}}</strong>
{{msg.body}}
</li>
</ul>
</div>
<input class="input" autofocus="true" ng-model="msg" ng-keydown="addMessage($event)" type="text" id="messageInput" placeholder="kirjota">
<script src="script.js"></script>
</body>
</html>
Im doing a chat, and i want to check if there is already a user with same name, so that there could not be two users with same nick. This does not work, and i can add many same nicks.
var usrref = new Firebase("https://(myapp).firebaseio.com/users");
$scope.users = $firebaseArray(usrref);
var taken = false;
for (var usr in $scope.users) {
if(usr.username == nick){
taken = true;
};};
if(taken == false){
$scope.users.$add({username:nick});
};
My messages is showing perfectly with ng-repeat in html, but i cant get this work. Its obviously something simple, but i have struggled too long with this.
Since you're using Angular, I'd suggest using Angular's forEach method. Here's an example of what you could do:
angular.forEach($scope.users, function(value, key) {
// put your code here
});
Edited
This should work for you. It checks your data after it has been loaded from Firebase. If the username is present, then it doesn't add the name. If it is not present, then it's added. You could check out the AngularFire API for $loaded().
var addNameToArray = true;
$scope.users.$loaded().then(function(data) {
angular.forEach(data, function(value, key) {
if(value.username === "John") {
addNameToArray = false;
}
});
if(addNameToArray) {
$scope.users.$add({username: "John"});
}
});
A for (var ... in ...) iterates over object keys. So if $scope.users is an array you'll get indexes: 0, 1, 2, ... in the usr variable. To iterate over an array you can use for example following construct:
$scope.users.forEach(function(user) {
});
But maybe instead of using an array it would be better to use an object indexed by username. Then you'll get immediate information if given user exists (users[nick] !== undefined) and you'll also avoid some other trouble. See Best Practices: Arrays in Firebase.
I have a small problem and I don't understand this thing:
When I add an item to TestiFactorys arr - array it does update to both controllers
On the other hand why does not TestiFactorys arr_len update to both controllers. And in TestiController why do I have to "manually" update TestControllers list1_length to make it update to view but I don't have to update TestiContollers list1 to make it update to view
I am assuming that my poor Javascript or Javascript variable scope understanding is causing this but i just don't see it.
I am using AngularJS version 1.2.16
<!DOCTYPE html>
<html ng-app="TestiApp">
<head>
<title></title>
</head>
<body>
<div ng-controller="TestController">
List items from controller: {{list1}}<br>
List item count:{{list1_length}}
<input type="text" ng-model="param"><br>
<button ng-click="list1_add(param)">asd</button>
</div>
<br><br>
<div ng-controller="TestController2">
List items from controller2{{list2}} <br>
List items count in from controller2: {{list2_length}}
</div>
<script src="scripts/angular.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
And this is my app.js:
var TestiApp = angular.module('TestiApp', [])
TestiApp.factory('TestiFactory',function() {
var arr = ['abx','cbs'];
var arr_len = arr.length;
return {
list : function() {
return arr;
},
add_to_arr : function(n) {
arr.push(n);
},
arr_len : function() {
arr_len = arr.length;
return arr_len;
}
}
}
);
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list();
$scope.list1_length = TestiFactory.arr_len();
$scope.list1_add = function (d) {
TestiFactory.add_to_arr(d);
$scope.param = '';
$scope.list1_length = TestiFactory.arr_len();
}
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list();
$scope.list2_length = TestiFactory.arr_len();
});
EDIT WITH SOLUTION
Here is working solution. Based to comments I decided to do more studying on Javascripts basics which
is of course the thing I should have done before trying to use this complex framework which uses Javascript. So now I have some basic understanding how to use references in Javascript and what primitive data types are. And based on that here is working version:
<!DOCTYPE html>
<html ng-app="TestiApp">
<head>
<title></title>
</head>
<body>
<div ng-controller="TestController">
List items from controller: {{list1()}}<br>
List item count:{{list1_len()}}
<input type="text" ng-model="param"><br>
<button ng-click="list1_add(param)">asd</button>
</div>
<br><br>
<div ng-controller="TestController2">
List items from controller2{{list2()}} <br>
List items count in from controller2: {{list2_length()}}
</div>
<script src="scripts/angular.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
And app.js:
var TestiApp = angular.module('TestiApp', [])
TestiApp.factory('TestiFactory',function() {
var arr = ['abx','cbs'];
return {
list : function() {
return arr;
},
add_to_arr : function(n) {
arr.push(n);
},
arr_len : function() {
return arr.length;
}
}
}
);
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list;
$scope.list1_add = TestiFactory.add_to_arr;
$scope.list1_len = TestiFactory.arr_len;
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list;
$scope.list2_length = TestiFactory.arr_len;
});
I've ran into this many times. Factories and services in angular are not like scopes...they work using references. The reason the array updates in your controllers is because the original reference was updated. The length is not updating because the number type is primitive.
This should work:
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list();
$scope.$watch('list1', function(list1) {
$scope.list1_length = list1.length;
});
$scope.list1_add = function (d) {
TestiFactory.add_to_arr(d);
$scope.param = '';
};
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list();
$scope.$watch('list2', function(list2) {
$scope.list2_length = list2.length;
});
});
I tried the Todo Example in Angular home page (No.2) and modified a little code which cause a wired problem.
When I add two Todo, the dispaly is ok which is displayed as “4 of 4 remain [archive]”,then I select 2 Todo item and click "acrhive". The result should be “2 of 2 remain [archive]", but acctually the display is “2 of 4 remain [archive]".
Then I replace ”for“ loop wiht "angular.forEach" function, the result is correct.
So anyone can explain what is the diffrence when I use between "for loop" and "angular.forEach"?
The coding is shown as belowing:
<html>
<head>
<meta charset="utf8">
<script src="js/angular.js"></script>
</head>
<body ng-app ng-controller="ToDo">
<span>{{remains()}} of {{total}} remain</span><span>[archive]</span>
<ul>
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.checked">{{todo.item}}
</input>
</li>
<form ng-submit="addTodo()">
<input type="text" ng-model="toDoitem" placeholder="add Todo List here"></input>
<span><input class="btn-primary" type="submit" value="Add"></input></span>
</form>
</ul>
<script>
var ToDo = function ($scope) {
$scope.todos = [
{item:"Discuss with my team",checked:false},
{item:"Mail to Jack",checked:false}
];
$scope.total = $scope.todos.length;
$scope.remains = function() {
var count =0;
for (var i=0;i<$scope.todos.length;i++) {
count += $scope.todos[i].checked?0:1
};
return count;
};
$scope.action= function($index) {
$scope.todos[$index].checked=!todos[$index].checked
$scope.remain += todos[$index].checked?-1:1;
};
$scope.addTodo = function() {
$scope.total ++;
$scope.todos.push({item:$scope.toDoitem,checked:false});
$scope.toDoitem = '';
};
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
for (var i=0;oldTodos.length-1;i++){
if (!oldTodos[i].checked) {
$scope.todos.push({item:oldTodos[i].item,checked:false});
};
};
/*
angular.forEach(oldTodos,function(todo){
if (!todo.checked) {
$scope.todos.push(todo);
};
});
*/
$scope.total = $scope.todos.length;
};
};
//http://jsfiddle.net
//http://plnkr.co/
</script>
</body>
</html>
In the context of your example there is nothing in particular different between angular.forEach and a standard for loop.
You don't appear to be pushing the same object into $scope.todos in the forEach, does the following help:
angular.forEach(oldTodos, function(todo) {
if (!todo.checked) {
$scope.todos.push({item: todo.item, checked: false});
};
});
You just need to have a look at the implementation for forEach for arrays and compare it with yours:
Angularjs forEach implementation for arrays:
for (key = 0; key < obj.length; key++)
iterator.call(context, obj[key], key);
And yours:
for (var i=0;oldTodos.length-1;i++){
if (!oldTodos[i].checked) {
$scope.todos.push({item:oldTodos[i].item,checked:false});
};
};
You could try:
for (var i=0; i < oldTodos.length; i++){
if (!oldTodos[i].checked) {
$scope.todos.push({item:oldTodos[i].item,checked:false});
};
};