I have two separate containers: one for outstanding tasks and one for completed tasks.
<li ng-repeat="(key, task) in requirements.tasks.outstanding track by $index">
<span class="handle"> <label class="checkbox">
<input type="checkbox" name="checkbox-inline" ng-model="completionOutstanding" ng-checked="task.completed" ng-change="taskChange(task, key)">
<i></i> </label> </span>
<p>
{{task.name}} <br />
<span class="text-muted">{{task.description}}</span>
<span class="date">{{task.date_entered}}</span>
</p>
</li>
Markup augmented with Angular for completed tasks:
<li class="complete" ng-repeat="(key, task) in requirements.tasks.completed track by $index">
<span class="handle"> <label class="checkbox">
<input type="checkbox" name="checkbox-inline" ng-model="completionCompleted" ng-checked="task.completed" ng-change="taskChange(task, key)">
<i></i> </label> </span>
<p>
{{task.name}} <br />
<span class="text-muted">{{task.description}} </span>
<span class="date">{{task.date_entered}}</span>
</p>
</li>
Angular Controller taskChange function used:
$scope.taskChange = function(task, key) {
if(task.completed == false) {
task.completed = true;
$scope.requirements.tasks.completed.push(task);
delete $scope.requirements.tasks.outstanding[key];
} else {
task.completed = false;
$scope.requirements.tasks.outstanding.push(task);
delete $scope.requirements.tasks.completed[key];
}
}
The functionality is working as it should, however, the row in the actual view persists. The row along with the data should be removed, but when this is tested the row remains there. As I add/remove tasks, many rows are accrued.
How can I add and remove the HTML rows in the list while adding/removing my data?
JSON Schema:
{
"tasks": {
"outstanding":[
{}, {}, {}, {}
],
"completed":[
{}, {}, {}, {}
]
}
}
You're confusing Arrays and Objects in your code:
For an object use:
<!-- repeat attr -->
ng-repeat="(key, value) in items"
// add an item
items[key] = value;
// remove an item
delete items[key];
For an array:
<!-- repeat attr -->
ng-repeat="item in items"
// add an item
items.push(item);
// remove an item
items.slice(items.indexOf(item), 1);
I think the problem is you are using delete to remove item from old list, that will not remove the "slot" of the item in the array, just set it to undefined
e.g. [a, b, c], after delete b, it becomes [a, undefined, c]
You may want to try splice to remove the item from array
Related
I have an input element being populated using the *ngFor loop fetching the data from another array. On selecting multiple checkboxes, I need their values to be pushed into my empty array 'selectedArr'.
Find below the code:
import { Component } from "#angular/core";
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
title = "CodeSandbox";
toDo = ["Test", "Eat", "Sleep"];
task: string;
addTask(task: string) {
this.toDo.push(task);
}
selectedArr = [];
deleteValue() {}
addSelected(i) {
let checkId = document.getElementsByClassName("i");
console.log(checkId);
if (checkId.checked === true) {
this.selectedArr.push(i);
}
console.log(this.selectedArr);
}
}
<div>
<div class="form-group">
<label>Add a Task: </label>
<input class="form-control" type="text" [(ngModel)]="task" />
</div>
<button (click)="addTask(task)">Add</button>
<br />
<br />
<div>
My To Do List:
<ul>
<li *ngFor="let todo of toDo, index as i">
<input class="i" type="checkbox" (click)="addSelected(i)" />
{{todo}}
</li>
</ul>
</div>
<div class="btn class">
<button class="btn btn-primary" (click)="deleteValue()">Delete</button>
</div>
</div>
Try like this:
.html
<li *ngFor="let todo of toDo, index as i">
<input class="i" type="checkbox" [(ngModel)]="checked[i]" (ngModelChange)="addSelected(todo,$event)" />
{{todo}}
</li>
.ts
checked = []
selectedArr = [];
addSelected(item,evt) {
if (evt) {
this.selectedArr.push(item);
}else {
let i = this.selectedArr.indexOf(item)
this.selectedArr.splice(i,1)
}
}
Working Demo
The getElementsByClassName method of Document interface returns an array-like object of all child elements which have all of the given class name(s). Since you are passing the index, you can access the clicked element like:
addSelected(i) {
let checkId = document.getElementsByClassName("i")[i];
console.log(checkId);
if (checkId.checked) {
this.selectedArr.push(i);
} else {
// Remove the index from selectedArr if checkbox was unchecked
let idx = this.selectedArr.indexOf(i)
if (idx > -1) this.selectedArr.splice(idx, 1)
}
console.log(this.selectedArr);
}
please, the things easy works easy. You needn't actually manually the array. You should use a function (*)
get selectedArray()
{
return this.toDo.filter((x,index)=>this.checked[index])
}
<li *ngFor="let todo of toDo, index as i">
<!--remove (ngModelChange) -->
<input class="i" type="checkbox" [(ngModel)]="checked[i]" />
{{todo}}
</li>
{{selectedArray}}
(*) this allow you "start" the app with some selected
The idea of this pattern is to manage different arrays. When user clicks on an option it selects/deselects it and option's value is pushed into/filtered from the corresponding array.
I am trying to write the universal method that will manage the array it was called with, at the moment it works fine with pushing values but doesn't work with filtering.
Angular Component Methods (doesn't work)
potatoesArray = [];
manageOptions($event, testingArray) {
const checkExistence = (array, value) => {
return !(array.indexOf(value) >= 0)
}
if ($event) {
// SPAN value
const optionValue = $event.target.innerText;
// Push if value isn't in array
if (checkExistence(testingArray, optionValue)) {
testingArray.push(optionValue);
// 'Remove' the value if it's in array
} else {
testingArray = testingArray.filter((option) => {
return option != optionValue;
})
}
}
Angular Component Methods (works if referenced to array directly)
potatoesArray = [];
manageOptions($event, testingArray) {
...
} else {
this.potatoesArray = testingArray.filter((option) => {
return option != optionValue;
})
}
}
Note
console.log(testingArray === this.potatoesArray) // true
Template implementation
<div class="option" (click)='manageOptions($event, this.potatoesArray)'>
<span>OPTION 1</span>
...
</div>
<div class="option" (click)='manageOptions($event, this.potatoesArray)'>
<span>OPTION 2</span>
...
</div>
<div class="option" (click)='manageOptions($event, this.potatoesArray)'>
<span>OPTION 3</span>
...
</div>
Remove this from the template implementation
<div class="option" (click)='manageOptions($event, potatoesArray)'>
<span>OPTION 1</span>
...
</div>
<div class="option" (click)='manageOptions($event, potatoesArray)'>
<span>OPTION 2</span>
...
</div>
<div class="option" (click)='manageOptions($event, potatoesArray)'>
<span>OPTION 3</span>
...
</div>
I have a list of checkboxes that are created using a ng-repeat, I use those checkboxes to get the IDs of the objects that are inside a list, these objects have a name property and a id property.
this is a object inside my categoryList
category = {
idCategory: 2,
name: 'myName'
};
And this is how I declare my checkboxes.
<div class="form-group">
<label>Select a category</label>
<label class="checkbox-inline" ng-repeat="category in categoryList">
<input type="checkbox" ng-model="idsCategory[category.idCategory]"> {{category.name}}
</label>
</div>
and then in my controller I get the ids like this
var categories= $scope.categoryList;
var idsSelected = [];
//get selected ids
for (var idCategory in categories) {
if (categories.hasOwnProperty(idCategory )) {
if (categories[idCategory ] === true) {
idsSelected .push(idCategory);
}
}
}
but now I want to hide and show some inputs in my HTML, if the user selects a category like "support" I want to show some inputs, but I don't know what condition put inside my ng-if since I declare my checkboxes ng-model like an array of ids like this ng-model="idsCategory[category.idCategory]"
how can I put my ng-if to hide the inputs I tried this but this doesn't work
<div id="b" ng-if="idsCategory.category.name=='Support'">
<div class="form-group">
<label>Support hours:</label>
<input class="form-control" placeholder="support houres">
</div>
</div>
Edited:
If we have HTML:
<div class="form-group">
<label>Select a category</label>
<label class="checkbox-inline" ng-repeat="category in categoryList">
<input type="checkbox" ng-model="idsCategory[category.idCategory]"> {{category.name}}
</label>
</div>
Conroller:
$scope.idsCategory = {};
$scope.categoryList = [{
idCategory: 1,
name: 'categoryA'
}, {
idCategory: 2,
name: 'recreation'
}, {
idCategory: 3,
name: 'develop'
}, {
idCategory: 4,
name: 'Support'
}];
Then we can use following ng-show:
<div id="b" ng-show="idsCategory[4]">
<div class="form-group">
<label>Support hours:</label>
<input class="form-control" placeholder="support houres">
</div>
</div>
See jsfiddle
In checkbox input we have ng-model="idsCategory[category.idCategory]", so idsCategory[4] stores info if category with idCategory = 4 is checked. That's why element with ng-show="idsCategory[4]" will be shown if category with idCategory = 4 is checked.
I am creating a sample todo application in which I can add/remove tasks but when I refresh the page, data is lost. So I decided to use localStorage to save the task lists and retrieve it when page refreshes.
I am able to do the same but I can retrieve the data only as a array list. How can i list tasks one by one stored in my localStorage and display it exactly like how it was before page load?
HTML CODE
<body ng-app="todoApp">
<div ng-controller="addTaskController" data-ng-init="init()">
<div class="container">
<h3>ToDo Application</h3>
<div class="form-group col-md-6">
<form ng-submit="addTask()" class="form-inline">
<input type="text" placeholder="Enter Your Task" ng-model="newTask" class="form-control">
<button type="submit" class="btn btn-primary">Add Task</button>
<div class="taskList">
<ol>
<li ng-repeat="task in tasks track by $index">{{task}} <i style="color:red;margin-left:10px;cursor:pointer;" class="fa fa-times" aria-hidden="true" ng-click="deleteTask()" data-toggle="tooltip" title="Delete Task"></i></li>
<p ng-show="tasks.length==0">No Tasks Available </p>
</ol>
</div>
</form>
</div>
</body>
JS CODE
var todoApp = angular.module('todoApp',[]);
todoApp.controller('addTaskController',function($scope){
$scope.tasks = [];
$scope.addTask = function() { // Function to add a task to list
if($scope.newTask == null) {
alert("Please enter a task");
} else {
$scope.tasks.push($scope.newTask);
localStorage.setItem("storedTasks", JSON.stringify($scope.tasks));
$scope.newTask = null;
}; // add() ends
}
$scope.deleteTask = function() {
$scope.tasks.splice(this.$index, 1);
localStorage.removeItem("storedTasks");
};
$scope.init = function() {
$scope.retrievedData = localStorage.getItem("storedTasks");
if($scope.retrievedData != null) {
$scope.tasks.push($scope.retrievedData);
} else {
tasks.length==0;
}
}
});
Before Page Reload
After Page Reload
How can i fix this
RetrievedData is an array you have to iterate over and push every item to the tasks object. What you are doing now is dumping the whole array into a single task.
if($scope.retrievedData != null){
$scope.retrievedData.forEach(function(item){
$scope.tasks.push(item);
})
}
Since you can only store string in local storage, which you did via JSON.stringify(), you need to undo it via JSON.parse(text[, reviver]) and then iterate over it.
Angular 1.4
I have a simple ng-repeat with a check box. The goal is to have the customer.Id added into the $scope.holdsChosenCustomerIds. I need $scope.holdsChosenCustomerIds to be dumb array like [3,78,445,789], basically whatever the user selects.
$scope.holdsChosenCustomerIds= [];
<div ng-repeat="customer in customers">
<input type='checkbox' ng-model="holdsChosenCustomerIds[$index]==???" ????????? />
</div>
stuck at this point
Just use instance of ng-repeat as model
Like this
<div ng-repeat="customer in customers">
<input type='checkbox' ng-model="customer.isChecked" />
</div>
You can get info of checked item from $scope.customers
If you need checked true item
you can try like this
$scope.holdsChosenCustomerIds= $scope.customers.filter(function(x){ return x.isChecked; });
You can write like this in your HTML using ng-change:
<div ng-repeat="customer in customers">
<input type='checkbox' ng-model="customer.selected" ng-change="selectUnselect()" />
</div>
And in your controller:
$scope.selectUnselect = function() {
var customer = this.customer;
if (customer.selected) {
$scope.holdsChosenCustomerIds.push(customer.id);
} else {
var idIndex = $scope.holdsChosenCustomerIds.indexOf(customer.id);
if (idIndex > -1) {
$scope.holdsChosenCustomerIds.splice(idIndex, 1);
}
}
};