Handling Array Building via Toggling Checkboxes in Angular 2 App - javascript

I am trying to come up with a simple toggle functionality where an array is built based on selections sent via checkboxes in my Angular 2 app. I seem to remember where you can handle toggling by setting one function to be equal to it's opposite, or something like that. These are the two functions I have for adding and removing array elements:
private onItemSelected(item)
{
if (item)
{
this.itemsArray.push(item);
console.log(this.itemsArray);
return this.itemsArray;
}
}
private onItemRemoved(item)
{
if (item)
{
this.itemsArray.splice(item);
console.log(this.itemsArray);
return this.itemsArray;
}
}
And then in my view I'm trying:
<md-checkbox (change)="onItemSelected('A') === onItemRemoved('A')">A</md-checkbox>
<md-checkbox (change)="onItemSelected('B') === onItemRemoved('B')">B</md-checkbox>
<md-checkbox (change)="onItemSelected('C') === onItemRemoved('C')">C</md-checkbox>
But this is not correct in it's current implementation. However, I do remember seeing something like this, though I can't remember the specific syntax. I've also considered using the "checked" JavaScript property in the conditional check. Would that be a better way to accomplish this? Or is there a simpler method to handle an array when items are added and removed based on checkbox selections?
UPDATE: After a suggestion from # I am closer. With this implementation I can toggle of and off for one item, and the array will reflect that correctly. However, for more than one item selection it doesn't work:
private isChecked: boolean = false;
private onItemSelected(discipline)
{
this.isChecked = !this.isChecked;
if (item && this.isChecked)
{
this.itemsArray.push(item);
console.log(this.itemsArray);
}
else {
if (item && !this.isChecked)
{
this.itemsArray.splice(item);
console.log(this.itemsArray);
}
return this.itemsArray;
}
}

i have posted a more simplified version without adding any extra properties . please try the code below
private onItemSelected(item)
{
const index: number = this.itemsArray.indexOf(item);
if(index < 0){
this.itemsArray.push(item);
console.log(this.itemsArray);
}
else if(index != -1){
this.itemsArray.splice(index,1);
console.log(this.itemsArray);
}
return this.itemsArray;
}

Related

trying to get the records only which are checked in vue JS

I am following this library for checkboxes. I went to look down the code and I see how it's declared and used.
At first in el-table we have #selection-change="handleSelectionChange". They have declared in data as empty array element like this
data() {
retrun {
multipleSelection: []
}
},
methods:handleSelectionChange(val) {
this.multipleSelection = val;
}
Now what I am checking is if I have some checkboxes clicked then I will get only those records not all. I am checking like this-
let data = []
console.log(this.multipleSelection.length);
if (this.multipleSelection.length == 0) {
data = JSON.parse(JSON.stringify(this.myapidata));
} else {
data = JSON.parse(JSON.stringify(this.multipleSelection));
}
But I am still getting complete data, not sure where I am missing the point. If anyone has experience in this, please guide.
When you select the checkboxes, the v-model variable updates itself with the selected values and this is what two-way binding does. Console the multipleSelection inside your method-
methods: {
handleSelectionChange() {
// It will console only selected items
console.log(this.multipleSelection);
}
}
You should see that only selected items are available inside multipleSelection.

Petite-Vue filtered array reactivity?

I played arround with Petite-Vue and really like it. Works fine with reactivity / ui updates and helpers like "$el" and "$refs" for easy form field handling / data binding.
Now I tried to have a reactive list with updates live if backend data (gundb) changes.
UI updates work fine if I list all array entries with "v-for".
If I try to filter the array of players by one team (object property "team") the UI is initialy correct rendered, but if a players name changed the update is pushed to gundb and by listener also to players array based on PetiteVue.reative(). So all is fine, but no UI update is triggered. Item is a Proxy as needed for (petite-)vue reactivity.
So it looks like a players.filter(...) call break reactivity. Also tried a method and getter inside of a component and also directly by write players.filter(...) to the html template.
Do I missing the right way how to trigger a re-render of changed filtered reactive array of objects?
I have a function to sync gundb "backend" changes to Petite-Vue.reactive object
gunArray2vue = (gunNode, vueArray) => {
gunNode.map().on((value, soul) => {
item = vueArray.find(item => item && item._ && item._['#'] === soul)
console.log('gunArray2vue', `soul=${soul}`, value, item)
if(!!item && value === null) {
// item in VUE but seems deleted... remove from vue array...
console.log("ToDeleteItem", item)
vueArray.splice(vueArray.indexOf(item), 1)
} else if(!value) {
console.log("Ignore creation of empty object")
return // don't add empty object...
} else if(item) {
//vueArray[vueArray.indexOf(item)] = value // update
console.log("UpdateItem")
item = value // update
} else {
console.log("AddArrayItem")
vueArray.push(value) // add new
}
})
}
Changed Value checked with console:
checked change in js console
But UI isn't refreshed.
Here the code in componente
tested as getter / function
//filteredPlayers: function() {
get filteredPlayers() {
if(this.form.nr || this.form.name) {
return this.players.filter(player =>
player.name.includes(this.form.name) || player.nr == this.form.nr
)
} else {
return this.players
}
}
The filtering is reactive to my input field! But changed name is ignored.
And here is a simpler getter function
get myPlayers() {
page.players
}
But ui isn't updated if an item changes without refresh.
So filtering works reactive, but changed items are not detected and re-rendered.
Also tried directly to use the unfiltered PetiteVue.reactive object like that.
<div v-for="player in page.players">{{player.nr}} {{player.name}}</div>
Rendering works fine, but also not updated on change.
Update
Noticed during my tests today, that updates work if I directly change my original object page.players, but not / no more if I use a reference to the original reactive object?
So I can't use the reactive object by reference without loose ui reactivity for item changes?
Update2
Add and remove an reactive array entry works fine!
Just update an item won't work. Tested different ways to set the item object / key -> val of object. Change isn't reactive.
Function with my tests
gun2arrayListener = (name, table) => {
console.log(`Register Listener Gun table "${name}"`)
DB.get(name).map().on((value, soul) => {
console.log("DEBUG", soul, value)
item = table.find(item => item?._['#'] === soul)
index = table.indexOf(item)
console.log('gun2array', `soul=${soul}`, value, item)
if(Object.is(item, value)) {
console.log("Skip unchanged item")
} else if(item && value === null) {
console.log("ToDeleteItem", item)
table.splice(index, 1)
} else if(!value) {
console.log("Ignore creation of empty object?!")
} else if(item) {
console.log("UPDATE", "ARRAY", item, value)
// !!! CHANGES NOT REACTIVE HERE !!!
// !!! method is triggered, changes looks good, but reload page needed to update UI !!!
//item = value
//TABLES[name][index] = value
//Object.assign(item, value)
//table.splice(index, 1, value)
//table.splice(index, 1); table.push(value)
for (const [key, val] of Object.entries(value)) {
console.log(`${key}: ${val}`)
//item[key] = val
store.players[index][key] = val
console.log(item)
}
} else {
console.log("AddNewGunNodeItem", value)
table.push(value) // add new
}
})
}
Strange... if I test reactivity from outside it works ?!
store.players[0].name = "BUM!" // works as needed in function... ?!
I noticed gun fires the listener twice, but that should result in correct updated array object, just changed to the new value twice...
I can't prevent that, because can't compare old object (vue proxy object) with the new object (plain object without vue proxy) to skip unchanged object here. Object.is results in false because of the Proxy arround...

Angular2: Directive variable change, update element

I'm currently trying to give classes to an wrapper that contains all of my app, i usually find this handy for giving certain states like when the header is fixed, or the menu's are opened etc.
So upon reading through some the docs of angular i should probably use an 'Directive'. Now i got this all set up and it looks like this:
constructor(private router:Router, #Inject(DOCUMENT) private document:Document, el:ElementRef, renderer:Renderer) {
this.setClasses(el, renderer);
}
setClasses(el:ElementRef, renderer:Renderer) {
renderer.setElementClass(el.nativeElement, 'header-fixed', this.headerFixed);
}
#HostListener("window:scroll", [])onWindowScroll() {
let number = this.document.body.scrollTop;
if (number > 100) {
this.headerFixed = true;
} else if (this.headerFixed && number < 10) {
this.headerFixed = false;
}
}
Now this is working perfectly but as you can see i'm toggling the headerFixed variable depending on scroll position. However i could of course run the function setClasses() again and it will work but is there anyway to subscribe/watch the variable and update automatically when changed?
Or is there even a better way of achieving wat i'm trying to do?
You can use #HostBinding like:
#HostBinding('class.header-fixed') get myClass() {
return someCondition;
}
Plunker Example

Check if property exists using React.js

I'm new to using react.js, and am trying to write a re-usable component that has an optional property passed to it. In the component, that optional property pulls data from a db using meteor, then I want to check if a property exists on the returned object (parent_task exists on task), and if exists, adds a link. This seems fairly simple, but I keep getting errors. Does anyone have any suggestions on what I might be missing? Is there a jsx gotcha that I'm missing?
<Header task={params.task_id} /> // rendering component with property
// Task List Header
Header = React.createClass({
mixins: [ReactMeteorData],
getMeteorData() {
var handle = Meteor.subscribe('tasks');
return {
taskLoading: ! handle.ready(),
task: Tasks.findOne({_id: this.props.task})
}
},
getParentTaskLink() {
if (!this.data.taskLoading) {
var current_task = this.data.task;
if (parent_task in current_task) { // or current_task.hasOwnProperty(parent_task)
console.log("parent_task exists!");
}
}
},
render() {
return (
<div className="bar bar-header bar-calm">
{this.getParentTaskLink()} // eventually return anchor element here
<h1 className="title">Hello World</h1>
</div>
)
}
});
what is the prop in question? how about
{this.props.propInQuestion ? link : null}
I figured this out. Apparently it was a syntax issue - you need to use a string when searching for properties in objects. The line below works:
if ('parent_task' in current_task)
For me works:
if ('myProperty' in this.props) {}
or
if (this.props.myProperty !== undefined) {}
or
if (this.props.hasOwnProperty('myProperty')) {}
Next condition will not work for number property, as 0 value will not work (such as for empty string):
if (this.props.MaxValue) {}
Check if a property exists using React.js
There are two options you can use. the && operator and If statement to check if the props exist.
Option 1 will check if the property exists then run the second part of the code. It works like an if without the if.
Option 1
this.props.property && this.props.property
Option 2
if(this.props.property){
this.props.property
}
This also works with function names.
You can use this also check to render components and tags.
This works for me
if(this.props.test === undefined){
console.log('props.test is not defined')
}
I suggest to try this elegant solution to check callback property on your component:
if(typeof this.props.onClickCallback === 'function') {
// Do stuff;
}
or applying destructuring:
const { onClickCallback } = this.props;
if(typeof onClickCallback === 'function') {
// Do stuff;
}
The most upvoted answer
props.propInQuestion ? 'a' : 'b'
Doesn't work if the prop is a boolean and you're trying to check for existence.
Based on How do I check if an object has a key in JavaScript? the fastest way is props.hasOwnProperty('propInQuestion'), with the caveat that this will not search the prototype chain.
In functional components, you can use like this.
if(props.myProperty){
//do something
}else{
//do something
}
if(props.hasOwnProperty('propertyName')){
//do something
} else {
//do something else
}
You need to return out of getParentTaskLink() with the link you need.
if (current_task.parent_task) {
return (link);
} else { return null; }

.filter jquery error

I'm having a problem, here is the javascript/jquery
getTextForDisplay: function() {
var displayText = "Select...";
var options = this.dataSource._data;
var selectedOptions = $.filter(options, function(index){
return this.selected;
});
if (selectedOptions.length == 1) {
displayText = "length1";
}
else if (selectedOptions.length > 1) {
displayText = "Multiple...";
}
return displayText;
}
});
so this is in regards to a multi-select dropdown box that has checkboxes, the options variable is an observable array pulling its data from a viewmodel, so what I am trying to do is to display "length1" if only one of the checkboxes is selected and to display "Multiple..." if more than one checkbox is selected, this seems pretty straightforward but I keep getting a error in when I run it. the error is c.replace is not a function and the error is in the jquery.min.js file. If I remove index from the .filter then it still doesn't work but it doesn't error out either.
jQuery doesn't define a jQuery.filter() function (at least, not in the public API). The .filter() it does define is a method for jQuery collections.
Perhaps jQuery.grep() is what you're looking for?
var selectedOptions = $.grep(options, function (option, index) {
return option.selected;
});
There is no such thing as $.filter(), unless you wrote it yourself or are using a plugin.
The correct syntax is
options.filter(function (index) {
...
});
Here's the documentation: http://api.jquery.com/filter/
You aren't properly using the jQuery.filter method, however, there is a documented method that does what you need. You should use documented methods rather than undocumented methods.
$.grep(options, function(){
return this.selected;
});
For this to work, options must be an array-like structure.

Categories

Resources