Selecting a subset of a JSON object & counting it - javascript

I'm having a hell of a time here, probably because I'm very new to Angular and I don't quite grok everything yet.
First the scenario, then hopefully some code:
I have a button that fetches a JSON object from an API call. It becomes $scope.collectors.
$http.post('get', $scope.formData).success(function(data) {
$scope.collectors = data.results;
...
Then I take that and make a big list of these items with checkboxes, so you can pick and choose which ones you want to work with. When you've selected the ones you want, you click another button to collect all of these together and bulk operate on them.
So that's the overall story. They task I'm having trouble with is twofold. First, I'm simply trying to count the number of items that are checked. I've done it like this:
JS:
$scope.selectedCollectors = {};
HTML:
<div ng-repeat="collector in collectors">
<input type="checkbox" name="collector-id"
value="{{collector.id}}"
ng-model="selectedCollectors[collector.id]">
</div>
<p>Debug: {{ selectedCollectors }}</p>
<p>There are {{ selectedCollectors.length }} items checked</p>
When I select items, the output of selectedCollectors is as expected:
{"8596784":true,"7458347":true}
But {{ selectedCollectors.length }} never increments or shows anything at all.
The second thing is basically what I'm trying to do is get the subset of the original JSON object to work with, based on the users selection. Other than looping through each item in $scope.collectors and comparing the ID to the IDs in selectedCollectors, is there a better more Angular-ish way to get this subset?
Something makes me feel like I should take this JSON object and turn it into a pure array, but maybe not...
Any advice or help is appreciated.

Here is my solution. http://jsfiddle.net/wittwerj/962wm/
First, I let angular add a "selected" property to the checked collector objects:
<div ng-repeat="collector in collectors">
<input type="checkbox" name="collector-id" value="{{collector.id}}"
ng-model="collector.selected" />
</div>
Then a second ng-repeat creates a filtered subset of selected collectors (see this question):
<div ng-repeat="collector in (selectedCollectors = (collectors | filter:{selected: true}))">
Note that the second ng-repeat is not generating any markup - just the selectedCollectors array, which can be accessed like a scope variable.

Related

How to two-way bind a checkbox using Angular?

I currently have an accordion with a bunch of options in the form of checkboxes. The user can select the checkboxes as expected however, I want to already have some of those checkboxes checked depending on certain conditions. The issue is sometimes that is determined after the page has loaded. Below are simplified examples to demonstrate my code (my code is for work and would not be able to share due to confidentiality issues).
My HTML looks like this:
<div class="row">
<div "ngFor="let value of filteredPeople" >
<div>
<input type="checkbox" (click)="selectPeople(value)" [checked]="checkedPeople.get(value)">
{{ value }}
</div>
</div>
</div
My Javascript:
public checkPeople() {
this.selectedPeople.forEach(element => {
this.checkedPeople.set(element, true);
});
}
To explain some variables and methods:
Variables:
filterPeople - a string array of all possible people
checkedPeople - a map with a KVP of string (the people) and boolean (whether or not their checkbox is checked)
selectedPeople - a string array of people whose checkboxes I want already checked
Methods:
selectPeople - checks the corresponding checkbox when user clicks on it
checkPeople - a method called when I want the specific checkboxes checked (these specific checkboxes change based on other factors so I cannot hard code it)
For some reason my checkPeople method does not seem to select the expected checkboxes, I am not sure why but I have a feeling it is to do with the fact that I have used "[checked]" in the HTML and that it should be something else. Can someone clarify the issue for me and help me identify a fix? (Note: as the title suggests, I am using Angular)
Edit:
I have just debugged my code and added breakpoints, the checkedPeople map has the correct mapping of people to true for each of the elements in selectedPeople which shows that the checkPeople method is working as expected. Therefore the issue must be with the [checked] attribute if I'm not mistaken. I cannot see why it wouldn't work though.
You should use [ngModel]="checkedPeople.get(value)"
instead of [checked]="checkedPeople.get(value)"
to initialize the checkbox and
(change)="checkUncheckPeople(value, $event)"
to update the value when you check or uncheck it, where
checkUncheckPeople(value, e) {
this.checkedPeople.set(value, e.target.value);
}
So, in conclusion, your HTML input element will be:
<input
type="checkbox"
[ngModel]="checkedPeople.get(value)"
(change)="checkUncheckPeople(value, $event)"
/>
If you choose to use an object instead of a map then you can also directly use
[(ngModel)]="checkedPeople[value]"
to two-way bind the variable

Angular - trouble with properties updating onchange from checkbox

I am attempting to use a checkbox in Angular in order to toggle the contents of an array. I am using property booleans to determine if 3 different boxes are checked and adjust the contents of the array accordingly. The array defaults to containing all 3 subarrays via declaring this.allNouns in ngOnInit(). When I click the first checkbox, I can see in the console that it is running the associated onchange function and setting the associated boolean to its opposite, but the interpolated string in the view does not change. When I click it again, it will change the view but now everything is one step behind. Also when it hits the console logs, it appears to load the prior length and not the length of the newly established this.allNouns. Below are the html and ts snippets associated with it. This is the first of the three checkboxes, but I plan to apply it to all when smoothed out.
TS
preloadedNouns: Boolean = true;
toggleData() {
if(this.preloadedNouns==false){
this.allNouns=this.nouns.concat(this.onlyUserNouns);
console.log('hitting first condition in toggledata', this.allNouns.length);
}
else {
this.allNouns=this.nouns.concat(this.stockNouns).concat(this.onlyUserNouns);
console.log('hitting second condition in toggledata', this.allNouns.length);
}
}
HTML
<div name="allNouns" [(ngModel)]="allNouns" [ngModelOptions]="{standalone: true}" ngDefaultControl>{{allNouns.length}}</div>
<div class="toggleDiv">
<label>Preloaded Nouns</label>
<input id="preloadedNounsCheck"
type="checkbox"
[checked]="preloadedNouns"
(change)="toggleData(); preloadedNouns = !preloadedNouns">
</div>
i don't clear about your nouns logic.
<div class="toggleDiv">
<label>Preloaded Nouns</label>
<input id="preloadedNounsCheck"
type="checkbox"
[checked]="preloadedNouns"
(change)="preloadedNouns = !preloadedNouns;toggleData()">
</div>
but i hope based on my understanding above code will help to you.
just reorder the function call in (change).

Need to get data out of an HTML form using vanilla Javascript

I'm trying to get some simple data out a form on a webpage. Should be pretty simple, but one, I can't use jQuery, it has to be plain JS, and two, it's on a legacy system so it has to work in IE11 only.
Here is an image of the form fields I'm working with:
I need to get the ID of the label and the value of the field as indicated in the red boxes. This is how they're mapping this to the DB. I have to pull these on the form, then put them in a spreadsheet.
The most simple way I've tried to do this is using:
document.getElementById('Section1_0').getElementsByTagName('*');
Of course this is kind of overkill since then I get back EVERY node in the DOM and then I would have to parse that out using something like JSON.parse() or something similar.
In short, if there is an easier way to get just the IDs and the values, that would be great. If I have to create an array and then iterate over that to pull the Ids and values I can do that as well. I've tried a few things, and I'm banging my head against the wall because the structure of the form isn't consistent.
Any help is greatly appreciated.
I hope this will help you.
const labels = document.getElementsByTagName("label");
Array.from(labels).forEach(label => {
const labelText = label.innerHTML;
const labelId = label.getAttribute('id');
console.log(labelText);
console.log(labelId);
});
<label id="label_id_1">Lable 1</label><br>
<label id="label_id_2">Lable 2</label><br>
<label id="label_id_3">Lable 3</label><br>
<label id="label_id_4">Lable 4</label><br>
<label id="label_id_5">Lable 5</label><br>

AngularJs get filtered input from ng-repeat to a Javascript variable?

I'm currently working with AngularJs and am filtering an input array with a number of select boxes. On the filtered result, I'm running an ng-repeat to display each element in my now filtered array. Now my question. I want to save the filtered input array as an javascript variable, to later display or print the whole result. I actually only want either the filtered input array saved to a javascript variable or even better, the results of each ng-repeat saved altogether in a variable but updating itself after applying a new filter or a filter again. I'm stuck here. Is there a smooth way to do this. Or do you have a even better idea what would work here? Thank's already.
Let's say we have a filter for languages and name:
<select class="form-control"
ng-options="l.language for l in languages"
ng-model="languageModel"
></select>
<select class="form-control"
ng-options="n.name for n in names"
ng-model="nameModel"
></select>
<ul ng-repeat="sq in input| filter:languageModel| filter:nameModel>
<li>Language: {{sq['Language']}}</li>
<li>Name: {{sq['Name']}}</li>
</ul>
Now I want something like :
$scope.var = ... // The filtered result.
You can directly store the array in your ng-repeat
<ul ng-repeat="sq in (filteredInput = (input| filter:languageModel| filter:nameModel))>
Now you can access $scope.filteredInput to get the filtered array
You can call the filter directly from javascript:
$scope.filteredInput = $filter('languageModel')($scope.input);
Where languageModel is the name of your filter.
Make sure to inject $filter in your controller.
By the way, it is weird to have the ng-repeat on the <ul> element. Something more appropriate would be to put it on the <li>:
<ul>
<li ng-repeat="sq in input| filter:languageModel| filter:nameModel>
<span>Language: {{sq['Language']}}</span>
<span>Name: {{sq['Name']}}</span>
<li>
</ul>
You can write your own filter function in your code behind, something like this
$scope.filterlanguage=function(item){
//add your condition if satisfies return or null
if(condition)
{
return item;
}
return null;
}

Save state of multiple Dynamic Components on ReactJS

Hi I have this component structure:
<ScheduleApp />
<ScheduleForm />
<TeamField />
My ScheduleApp contains a form called ScheduleForm and under this form I have a field where users can specify a number of teams and depends on the number the number of TeamField is created.
My form looks like this:
And what I wanted is to save all the teams' names under my ScheduleApp component. I can save all the other states with no problem, example: the No. of Teams field with no problem but I'm stuck on how to save the Team Name fields in an array.
Here is my poor attempt on saving the array but it looks like it saves all the keystrokes I've made probably because I triggered it onChange event.
How am I suppose to solve this problem and just save the dynamic components on the parent components' state?
Now here are my codes on jsfiddle for some reason I can't make it run on the site but will post it there for easier access.
Hope I made it clear. Any help would be much appreciated!
You are pushing the current content of text box into the array on every change/keystroke. Instead what you should do is text box 1 should only modify the first index in your array. And text box 2 should only modify second field in your array and so on. On each change, replace entire content with new content.
Or a cleaner approach would be to store a teams object. And send a team number field too in the on change handler against which you can store the team name.
<input className="form-control" type="text" ref="teamName"
onChange={this.handleChange.bind(null, 'team1')} /> // pass any index or string instead of team1
...
handleChange(teamIndex, teamName) {
let { teams } = this.state;
teams[teamIndex] = teamName;
this.setState({teams: teams};
}

Categories

Resources