splice is creating NULL entry while removing the entry from an array - javascript

In my Angular5 application when I tried to remove the entries from the peoples array which is contained in selectedPersonArray using splice keyword is occasionally creating null entry in the peoples array. The code I have done looks like this:
import { Component } from '#angular/core';
import { DragulaService } from 'ng2-dragula/ng2-dragula';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
selectedPersonArray = [];
peoples = [
{
id: 7,
firstName: 'Sobin 7',
lastName: 'Thomas 7'
}
];
people = [
{
id: 1,
firstName: 'First Name 1',
lastName: 'Last Name 1'
},
{
id: 2,
firstName: 'First Name 2',
lastName: 'Last Name 2'
},
{
id: 3,
firstName: 'First Name 3',
lastName: 'Last Name 3'
},
{
id: 4,
firstName: 'First Name 4',
lastName: 'Last Name 4'
}
];
toggleItemInArr(arr, item) {
const index = arr.indexOf(item);
index === - 1 ? arr.push(item) : arr.splice(index, 1);
}
addThisPersonToArray(person: any, event) {
if (!event.ctrlKey) {
this.selectedPersonArray = [];
}
this.toggleItemInArr(this.selectedPersonArray, person);
}
isPersonSelected(person: any) {
return (this.selectedPersonArray.indexOf(person) !== -1);
}
constructor(private dragula: DragulaService) {
dragula.setOptions('second-bag', {
copy: function (el, source) {
return source.id === 'source';
},
removeOnSpill: true,
copySortSource: false,
accepts: function(el, target, source, sibling) {
return target.id !== 'source';
}
});
}
ngOnInit() {
this.dragula
.out
.subscribe(value => {
for(let select of this.selectedPersonArray){
let i= 0;
for (let entry of this.peoples) {
if(entry.id == select.id){
let index = this.people.indexOf(select.id);
if (this.peoples.length >0){
this.peoples.splice(i, 1);
}
}
i++;
}
}
console.log("on after loop "+JSON.stringify( this.peoples));
this.selectedPersonArray.length = 0;
});
}
}
app.component.html
<table border=1 bgcolor="yellow">
<tbody id ='source' [dragula]='"second-bag"' [dragulaModel]="people">
<tr *ngFor="let person of people" >
<td>{{person.id}}</td>
<td>{{person.firstName}}</td>
<td>{{person.lastName}}</td>
</tr>
</tbody>
</table>
<table border=2>
<tbody id ='dest' [dragula]='"second-bag"' [dragulaModel]="peoples">
<tr *ngFor="let person of peoples" (click)="addThisPersonToArray(person, $event)" [class.active]="isPersonSelected(person)">
<td>{{person.id}}</td>
<td>{{person.firstName}}</td>
<td>{{person.lastName}}</td>
</tr>
</tbody>
</table>
Actually what I want was is to delete multiple items selected using control key from 'dest' container of ng2-dragular second-bag.And it is working but it is creating null entries also

Can you try this?
this.peoples
.filter(people => !this.selectedPersonArray
.find(selectdPeople => people.id === selectdPeople.id)
);

I like the answer using filter and find. Here's another alternative using a loop.
I worked on a jsfiddle with what I suspect you were trying to do. Is this this is similar to what you intended?
I updated the search to work backwards so that the splice wouldn't alter the parts of the array that had not been searched through yet.
The jsfiddle can be found here: https://jsfiddle.net/vboughner/wfeunv2j/
this.selectedPersonArray = [
{
"id": "hello1",
"name": "something1"
},
];
this.peoples = [
{
"id": "hello1",
"name": "something1"
},
{
"id": "hello2",
"name": "something2"
},
{
"id": "hello3",
"name": "something3"
},
];
console.log(this.selectedPersonArray);
console.log(this.peoples);
for (let select of this.selectedPersonArray) {
for (let i = this.peoples.length - 1; i >= 0; i--) {
if (select.id == this.peoples[i].id) {
this.peoples.splice(i, 1);
}
}
}
console.log("on after loop " + JSON.stringify( this.peoples));
this.selectedPersonArray.length = 0;
The output looks like this:
on after loop [{"id":"hello2","name":"something2"},{"id":"hello3","name":"something3"}]

Related

Vue.draggable - swapping between two list

I have a problem. I need to organaze two draggable table like swapping.
1 table: have 7 fixed items.
2 table: Other items.
When you swapping items from the second table to the first, a dialog box should appear to confirm swapping.
I did swap for first list, but not understand how to do for two table.
my code now:
<template>
<table>
<draggable v-model="items" tag="tbody" :move="handleMove" #end="handleDragEnd" :options="{animation:500}">
<tr v-for="item in items" :key="item.id">
<td>{{ item.id }}</td><td>{{ item.name }}</td><td>{{ item.age }}</td>
</tr>
</draggable>
</table>
</template>
<script>
import draggable from "vuedraggable";
export default {
components: {
draggable,
},
data() {
const items = [
{ id: 1, name: "Bianka Effertz", age: 37 },
{ id: 2, name: "Mckayla Bogan", age: 20 },
{ id: 3, name: "Estevan Mann", age: 17 },
{ id: 4, name: "Cloyd Ziemann", age: 55 }
]
return { items }
},
computed: {
orders() {
return this.items.map(x => x.id)
}
},
methods: {
handleDragEnd() {
this.$toast.show('dragEnd')
this.futureItem = this.items[this.futureIndex]
this.movingItem = this.items[this.movingIndex]
const _items = Object.assign([], this.items)
_items[this.futureIndex] = this.movingItem
_items[this.movingIndex] = this.futureItem
this.items = _items
},
handleMove(e) {
const { index, futureIndex } = e.draggedContext
this.movingIndex = index
this.futureIndex = futureIndex
return false // disable sort
}
}
</script>

Join multiple array maps in ReactJs

im new in reactjs, is that possible to do in reactjs,like mysql inner join, here my sample code.
{dataCustomer.map((customer) => (
<tr>
<td>{customer.custid}</td>
<td>{customer.custname}</td>
<td>{customer.mailingaddr}</td>
<td>{customer.stateid}</td>
<td>{customer.districtid}</td>
<td>{customer.postcode}</td>
</tr>
))}
{dataState.map((state) => (
<tr>
<td>{state.stateid}</td>
<td>{state.statename}</td>
</tr>
))}
how to join array map data from customer.stateid & state.stateid to call state.statename without use SQL syntax?..Is that possible?
This should work
let joinedData=[]
dataCustomer.forEach((customer)=>{
let st= dataState.filter((state)=>state.stateid===customer.stateid);
if(st.length>0)
joinedData.push({...customer,statename:st[0].statename})
})
joinedData array will now contain the customer objects with the corresponding statename and you can use it as
{joinedData.map((customer) => (
<tr>
<td>{customer.custid}</td>
<td>{customer.custname}</td>
<td>{customer.mailingaddr}</td>
<td>{customer.stateid}</td>
<td>{customer.districtid}</td>
<td>{customer.postcode}</td>
<td>{customer.statename}</td>
</tr>
))}
It is not exactly the same but I think the function below that I wrote can help you:
let customers = [{
name: "Foo",
stateid: 1
},
{
name: "Boo",
stateid: 3
},
{
name: "Goo",
stateid: 2
},
{
name: "Zoo",
stateid: 2
},
];
let states = [{
name: "State1",
id: 1
},
{
name: "State2",
id: 2
},
];
function join(customers, states, column1, column2) {
return customers.map(customer => {
states.forEach(state => {
if (customer[column1] === state[column2]) {
customer["state"] = { ...state };
}
})
return customer;
})
}
console.log(join(customers, states, "stateid", "id"))
Note that column1 and column2 parameters are the properties you are joining on.

uncheck a checkbox which is checked and freezed with a condition in Angular 5

I have a table that iterates on JSON values, i have checkbox in the first column
requirement: when 5 checkboxes are selected, the user shouldn't be able to select the 6th checkbox, but he can deselect any in the 5 checkboxes
current scenario: i am able to freeze the checkboxes when the user selects 5 checkboxes but it isn't allowing me to deselect the selected checkbox
<checkbox [forbidden]="isFull() && !Selected" [ngModel]="Selected" (ngModelChange)="Change(Result, $event)"></checkbox>
checkbox is a custom component in my code base
isFull() {
return someService.Slots()===0; // availableSlots returns 5
}
Change(Result, $event){
// some code irrelevant to the checkbox logic
// Result holds the JSON value for iterating row
}
Please provide a working plunker or any online editor for better understanding
Thanks in advance
Hope this helps you!, You can optimize this and modified according to your need.
Working sample plunker
Template file:
template: `
<ul>
<ng-container>
<li *ngFor="let item of list">
<input
type="checkbox"
value="{{item.value}}"
[disabled]="item.disabled"
(change)="onCheckboxChange($event, item)"
/>
{{item.label}}<br>
</li>
</ng-container>
</ul>
<pre> {{checkedList | json}} </pre>
`
Class file
export class App {
name: string;
checkedList: any = [];
list: any = [
{'label': 'A', 'value': 'a', 'disabled': false},
{'label': 'B', 'value': 'b', 'disabled': false},
{'label': 'C', 'value': 'c', 'disabled': false},
{'label': 'D', 'value': 'd', 'disabled': false},
{'label': 'E', 'value': 'e', 'disabled': false},
{'label': 'F', 'value': 'f', 'disabled': false},
{'label': 'G', 'value': 'g', 'disabled': false}
];
constructor() {
}
onCheckboxChange(e, item) {
if(e.target.checked) {
this.checkedList.push(item);
} else {
let index = this.checkedList.findIndex(obj => item.value === obj.value);
if(index > -1) {
this.checkedList.splice(index,1);
}
}
if(this.checkedList.length > 4) { // *change available slots*
let unCheckedList = this.list.filter((obj) => {
let isCheck = this.checkedList.find((item) => {
return item.value === obj.value
});
obj.disabled = !isCheck ? true : false;
return !isCheck;
});
} else {
this.list.map((obj)=>{
obj.disabled = false;
});
}
}
}
shouldn't be "isFull() && !Selected"? because you want to freeze unselected ones, but still are able to deselect the selected ones.
UPDATE
Try this:
import { Component } from "#angular/core";
import { list } from './list';
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
list: Array<any>;
checked = [];
shouldCheckboxesBeDisabled = false;
ngOnInit() {
this.list = list;
this.recheckDisablingStatus();
}
recheckDisablingStatus() {
this.shouldCheckboxesBeDisabled = this.list.filter(item => item.checked).length >= 5;
}
uncheckIfAlreadyChecked(itemIndex) {
const isChecked = this.list[itemIndex].checked;
this.list[itemIndex].checked = isChecked ? false : isChecked;
this.recheckDisablingStatus();
}
}
And in the template:
<table border="1">
<thead>
<td>ID</td>
<td>Name</td>
<td>Checked</td>
<td>Uncheck if Already Checked</td>
</thead>
<tbody>
<tr *ngFor="let item of list; let i = index">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>
<input
[disabled]="shouldCheckboxesBeDisabled && !list[i].checked"
type="checkbox"
[(ngModel)]="list[i].checked"
(change)="recheckDisablingStatus()">
</td>
<td><button (click)="uncheckIfAlreadyChecked(i)">Uncheck If Checked</button></td>
</tr>
</tbody>
</table>
Here's a Working Sample StackBlitz for your ref.
ORIGINAL ANSWER
Give this a try:
<table border="1">
<thead>
<td>ID</td>
<td>Name</td>
<td>Checked</td>
</thead>
<tbody>
<tr *ngFor="let item of list$ | async; let i = index">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>
<input
[disabled]="shouldCheckboxesBeDisabled && checked.indexOf(item.id) < 0"
type="checkbox"
(change)="onCheckBoxChange(item.id, $event.target.checked)">
</td>
</tr>
</tbody>
</table>
And in your Component:
import { Component } from "#angular/core";
import { Observable, of } from "rxjs";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
list$: Observable<Array<any>>;
checked = [];
shouldCheckboxesBeDisabled = false;
constructor(private http: HttpClient) {}
ngOnInit() {
// this.list$ = this.http.get<Array<any>>('/assets/data.json');
this.list$ = of([
{
id: 1,
name: "Name 1",
checked: false
},
{
id: 2,
name: "Name 2",
checked: true
},
{
id: 3,
name: "Name 3",
checked: false
},
{
id: 4,
name: "Name 4",
checked: true
},
{
id: 5,
name: "Name 5",
checked: false
},
{
id: 6,
name: "Name 6",
checked: true
},
{
id: 7,
name: "Name 7",
checked: false
},
{
id: 8,
name: "Name 8",
checked: true
},
{
id: 9,
name: "Name 9",
checked: false
},
{
id: 10,
name: "Name 10",
checked: true
}
]);
}
onCheckBoxChange(itemId, checked) {
if(checked) {
this.checked.push(itemId);
} else {
const itemIndexToRemove = this.checked.indexOf(itemId);
this.checked.splice(itemIndexToRemove, 1);
}
this.shouldCheckboxesBeDisabled = this.checked.length >= 5;
}
}
Here's a Working Sample StackBlitz for your ref.

Knockout Table : Highlight a Table Row

I have an Example Fiddle here. In this Table I wish to achieve Highlighting a Particular Row selected. If unselected Row should not be highlighted.
One of many sample I found Fiddle but I am unable to incorporate them inside my Example Fiddle Above.
Below is the HTML Code which shows basic Table.
<table id="devtable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr data-bind=" click: $parent.select ">
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
<td data-bind="text: Status"></td>
</tr>
</tbody>
ID :
Name :
Status :
Here is the knockout function to do manipulations
<Script>
var rowModel = function (id, name, status) {
this.ID = ko.observable(id);
this.Name = ko.observable(name);
this.Status = ko.observable(status);
};
var myData = [{
id: "001",
name: "Jhon",
status: "Single"
}, {
id: "002",
name: "Mike",
status: "Married"
}, {
id: "003",
name: "Marrie",
status: "Complicated"
}];
function MyVM(data) {
var self = this;
self.items = ko.observableArray(data.map(function (i) {
return new rowModel(i.id, i.name, i.status);
}));
self.select = function(item) {
self.selected(item);
self.enableEdit(true);
};
self.flashCss = ko.computed(function () {
//just an example
return 'flash';
});
self.selected = ko.observable(self.items()[0]);
self.enableEdit = ko.observable(false);
self.changeTableData = function() {
// How do I change the Data here and it should also reflect on the Page.
// If I do binding depending on condition it gives me error
if(true){
var myData = [{
id: "001",
name: "Jhon",
status: "Single"
}, {
id: "002",
name: "Mike",
status: "Married"
}, {
id: "003",
name: "Marrie",
status: "Complicated"
}];
}
else{
myData = [{
id: "111",
name: "ABC",
status: "Single"
}, {
id: "222",
name: "XYZ",
status: "Married"
}, {
id: "3333",
name: "PQR",
status: "Complicated"
}];
}
}
}
ko.applyBindings(new MyVM(myData));
</script>
CSS code below
.flash { background-color: yellow; }
You can use the css binding to add the .flash class based on the currently selected value:
<tr data-bind="click: $parent.select,
css: { flash: $parent.selected() === $data }">
...
</tr>
If you don't like this logic being defined in the view, you can pass a reference to the selected observable and create a computed property inside your RowModel:
var RowModel = function( /* ... */ selectedRow) {
// ...
this.isSelected = ko.pureComputed(function() {
return selectedRow() === this;
}, this);
}
Here's the quick fix in your fiddle:
http://jsfiddle.net/wa78zoe4/
P.S. if you want toggle-behavior, update select to:
self.select = function(item) {
if (item === self.selected()) {
self.selected(null);
self.enableEdit(false);
} else {
self.selected(item);
self.enableEdit(true);
}
};

AngularJS pass filtered value to scope value

Good morning, i'm new to angularjs and want to practice it more, and here i have a question regarding a simple case while trying to learn to build my own angularjs webpage.
I have these two sets of data
$scope.data1 = [{ id: 1, name: "abc" },
{ id: 2, name: "efg" }]
$scope.data2 = [{ id: 1, info: "this is abc" },
{ id: 2, info: "absolutely not abc"}]
$scope.user = {
id: "",
name: "",
info: ""
}
and i have this input
<input ng-blur="passTheValue()" ng-model="user.idx" ng-type="text" placeholder="write name here"></input>
where i can write name on the text box.
my question is, how to pass all the value from data1 and data2 to $scope.user based on what input i have entered? For example, i write "abc" on the textbox, then my $scope.user will contain
id: 1, name: "abc", info: "this is abc"
i've tried to use $filter but i'm stuck at passing the value to the scope.
i'm sorry for my English, it's not my main language.
This is not the classical usecase for a filter: Do the processing of your data in the passTheValue() function.
this.passTheValue = function(){
$scope.data1.forEach(function(value, index, array){
if(value.name == $scope.idx){
$scope.user = {id: value.id, name: value.name, info: $scope.data2[index] }
}
})
}
HTML
<input ng-blur="passTheValue(user.idx)" ng-model="user.idx" ng-type="text" placeholder="write name here"></input>
Angular
$scope.passTheValue = function(name) {
angular.forEach($scope.data1, function(value, key){
if(value.name == name){
$scope.user.id = value.id;
$scope.user.name= value.name;
$scope.user.info = $scope.data2.filter(function(v) {
return v.id === value.id; // Filter out the appropriate one
})[0].info;
console.log($scope.user.id);
console.log($scope.user.name);
console.log($scope.user.info);
}
});
}
In your HTML , I've replaced the user.idx by name because you're searching by name. Sample on Plunker : https://plnkr.co/edit/bumDWC713dVWGnKoO5G3?p=preview
<body ng-app='app'>
<div ng-controller='appCtrl'>
<input ng-blur="passTheValue()" ng-model="name" ng-type="text" placeholder="write name here">
</div>
</body>
In your javascript, I add to simply search methods.
var app = angular.module('app',[])
.controller('appCtrl',function(){
$scope.data1 = [{
id: 1,
name: "abc"
},
{
id: 2,
name: "efg"
}];
$scope.data2 = [{
id: 1,
info: "this is abc"
},
{
id: 2,
info: "absolutely not abc"
}];
$scope.name = "";
$scope.user = {
id: "",
name: "",
info: ""
};
function findIdByName(name) {
for (var i = 0 ; i< $scope.data1 ; i++) {
if($scope.data1[i].name == name)
return $scope.data1[i].id;
}
return -111 ; //Assume that it's an impossible ID
}
function findInfoById(id) {
for (var i = 0 ; i< $scope.data2 ; i++) {
if($scope.data1[i].id == id)
return $scope.data1[i].info;
}
return -111 ; //Assume that it's an impossible Info
}
$scope.passTheValue = function(){
var id = findIdByName($scope.name);
if(id != -111){
var info = findInfoById(id);
if(info != -111){
$scope.user.id= id;
$scope.user.name = $scope.name;
$scope.info = info;
}else {
console.log(id,"Id doesn't exist in $scope.data2")
}
}else {
console.log(name,"name doesn't exist in $scope.data1")
}
}
});

Categories