Cannot save/push array of objects to parse backend - arrays

I was attempting to add an array to the parse.com backend. I created an array:
var addHoles = function () {
$scope.holeArray = [];
for (var i = 0; i < 18; i++) {
$scope.holeArray[i] = {
number: i + 1,
par: '',
distance: '',
handicap: ''
};
}
console.log($scope.holeArray);
return $scope.holeArray;
};
and then used ng-repeat to display the array and ng-model to allow the user to change the array.
<div ng-repeat="hole in holeArray" class="row">
<div class="form-group">
<div class="col-md-2">
<div class="form-group form-md-line-input">
<input type="text" class="form-control" id="form_control_1" ng-model="hole.number" readonly>
<label for="form_control_1">Hole Number</label>
</div>
</div>
I was getting an unusual error from parse. and could not get parse to save the array.

It turns out the issue was that when you use ng-repeat angularjs adds a $$hashKey. This $$hasKey conflicts with parse's backend formatting requirements. So, to fix the issue all I had to do was use "track by" in my ng-repeat.
<div ng-repeat="hole in holeArray track by hole.number" class="row">
This took me hours to figure out. Hopefully it saves someone else time and headache.

Related

get values from each ng-repeat input elements

I have the following code where I have added 5 input texts via ng-repeat and now am trying to fetch each of the input element's values. I am hitting some roadblock, so please help me out on how to fetch individual values.
HTML:
<form class="quick-add-form" method="post">
<label class="quick-add-label">Enter the catalog number and quantity</label>
<div class="quick-add">
<div class="catalog-list">
<label class="catalog-number-label" for="catalog-number-input">Catalog Number:</label>
<div ng-repeat="values in catalogNumber(number) track by $index">
<input id="catalog-number-input-{{$index}}" class="catalog-number-input"
type="text" ng-model="catalog.description" validate-input>
</div>
</div>
<div class="qnty-list">
<label class="pdt-qnty-label" for="pdt-qnty-input">Quantity:</label>
<div ng-repeat="values in catalogNumber(number) track by $index">
<input id="pdt-qnty-input-{{$index}}" class="pdt-qnty-input" type="number" pattern="[0-9]*"
inputmode="numeric" min="1" max="999" ng-model ="catalog.quantity" name="qty"
maxlength="3">
</div>
</div>
</div>
<div>
<button type="submit" class="btn btn-danger cta-button quick-add-btn"
ng-click ="quickAdd(catalog)">Add to List</button>
</div>
</form>
and controller:
$scope.catalog = {};
$scope.catalogNumber = catalogNumber;
$scope.initializeModal = initializeModal;
$scope.quickAdd = quickAdd;
function catalogNumber(num) {
return new Array(num);
}
function quickAdd(val) {
console.log(val);
}
function init() {
$scope.number = 5;
$scope.catalog.quantity = 1;
}
I am pretty sure its because of indexing and which is why by adding value in one input, its adding same value in all at once. But I am not sure how/where to use the $index properly to achieve the result.
Thanks.
Perhaps a better way would be to use the model? For example:
<div ng-repeat="values in catalogNumber(number) track by $index">
<input
id="catalog-number-input-{{$index}}"
class="catalog-number-input"
type="text"
ng-model="catalog.description[$index]"
validate-input>
</div>
Now in your controller:
catalog.description = [];
Then you have an array of objects, which you can perform your math on:
var total = _.sum(Object.values(catalog.description));
Edit: I had forgot I was using Lodash/Underscore there, but if you wanted to use standard JS you could use a standalone method, or reduce etc.,

Angular - Binding data to dropdownlist never clears out previous items on updating (keeps old items plus add new)

Hopefully a simple Angular binding question.
I have a TextBox on my Angular 4 [x.component.html] that has an (input) event tied to it, so each time the user types in a character into the textbox it reaches out to a method in the [x.component.ts] typescript file - which then retrieves data from a service to populate a local array of data in the typescript file - which is bound to a dropdownlist on the [x.component.html]. This process functionally works fine.
However the problem I am having is that when it updates the data in the local array, it is not clearing out the previous data in the dropdown, so the dropdown list ends up getting populated with lots of duplicate data. Has anyone experienced this same problem before? The local array of items seems to have the correct number of items in it, it just seems to keep populating the dropdownlist with the items without ever clearing the previous.
Thanks so much for your help.
Please note I have cut the code down to only the relevant parts for brevity.
[x.component.ts]
export class CreateComponent {
testService: TestService;
valueList: testValue[];
constructor(testService: TestService) {
this.testService = TestService;
}
ngOnInit() {
}
FieldChanged(event: any, controlNameToPopulate: string){
if (event.target.value.length >= 9) {
this.testService.getRecords(event.target.value).subscribe((data: any[]) => {
if (data.length != 0){
document.getElementById(controlNameToPopulate).hidden = false;
//this.valueList.slice();
this.valueList = data;
}
});
}
}
}
[x.component.html]
<div class="row">
<div class="col-md-6">
<nb-card>
<nb-card-header>Testing with Updating dropdownlist</nb-card-header>
<nb-card-body>
<form [formGroup]="formGrp">
<div class="form-group row">
<label class="col-sm-3 col-form-label">Quick search</label>
<div class="col-sm-9 input-group">
<input type="text" class="form-control input-sm" style="width: 50%" id="txtbx_ValTest" formControlName="testVal" (change)="FieldChanged($event, 'ddValuesToUpdate')">
<select id="ddValuesToUpdate" class="btn btn-secondary dropdown-toggle" style="width: 50%" hidden>
<option *ngFor="let val of valueList" [value]="val.id">{{val.id}}</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="offset-sm-3 col-sm-9">
<button type="submit" class="btn btn-success pull-right">Add</button>
</div>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

Refresh ng-repeat data

I have a big list containing all of my data, and I have another shorter list containing only the selected data.
Originally, all the data is selected so both lists are identical, and the user must uncheck the checkbox of the unwanted data, and then the unchecked data must disappear from the selected_data_list.
When the page is loaded, the two lists are being filled correctly. But when I uncheck the unwanted data, the selected_data_list is not updating.
I tried to use $scope.$apply(), but it gave me this error:
Error: $rootScope:inprog
Action Already In Progress
Here is my code:
Complete list:
<div ng-controller="BrainRegionsCtrl">
<div ng-repeat="region in brain_regions">
<label>
<input type="checkbox"
name="checkbox_brain_region__included"
id="checkbox_brain_region_{/region.id/}"
value="{/region.id/}"
ng-model="region.show"
ng-change="update_selected_Brain_regions(region)">
<b>{/region.name/}</b>
</label>
</div>
</div>
Selected regions list:
<div ng-controller="BrainRegionsCtrl">
<label ng-repeat="region in selected_brain_regions">
<input type="radio" name="radio_brain_regions_graphical_search_soma" value="{/region.id/}">
<b>{/region.name/}</b>
</label>
</div>
Controller:
ngApp.controller('BrainRegionsCtrl', function ($scope, $http) {
$scope.brain_regions = [];
$scope.selected_brain_regions = [];
$scope.update_selected_Brain_regions = function (region) {
for (var i = 0; i < $scope.brain_regions.length; i++) {
var current_region = $scope.brain_regions[i];
if (current_region.id === region.id) {
if (region.show) {
$scope.selected_brain_regions.push(current_region);
}
else {
$scope.selected_brain_regions.splice(i,1);
}
}
}
console.log($scope.selected_brain_regions);
};
});
Here is a jsfiddle
Thank you.
Just try to use $rootScope.
Because you give the ng-controller="BrainRegionsCtrl" for two div that's why the $scope.selected_brain_regions will go to the initial state in the second div.
OR
you should give the ng-controller="BrainRegionsCtrl" to the root div which contains the two parts of your code..
Please check with this code and let me know whether it solves your issue. Also please check this working plnkr of your example scenario.
Template:
<div ng-repeat="region in brain_regions">
<label>
<input type="checkbox"
name="checkbox_brain_region[$index]"
id="checkbox_brain_region[region.id]"
value="region.id"
ng-model="region.show"
ng-change="update_selected_Brain_regions(region)">
<b>{{region.name}}</b>
</label>
</div>
<br>
<label ng-repeat="region in selected_brain_regions">
<input type="radio" name="radio_brain_regions_graphical_search_soma[$index]"
ng-model="region.show" value="region.id">
<b>{{region.name}}</b>
</label>
Controller:
$scope.update_selected_Brain_regions = function (region) {
for (var i = 0; i < $scope.brain_regions.length; i++) {
var current_region = $scope.brain_regions[i];
if (current_region.id === region.id) {
if (region.show) {
$scope.selected_brain_regions.push(current_region);
} else {
var index = $scope.selected_brain_regions.map(function(x){ return x.id; }).indexOf(current_region.id);
$scope.selected_brain_regions.splice(index,1);
}
}
}
};
AngularJS promises already call .apply() on their callbacks. You cannot call .apply again inside the callbacks since they're already being .applied, and the error "In Progress" tells exactly that. Just remove the .apply call and it will work, unless you have further errors.
Your issue because of index update, so try track by $index, should work.
<label ng-repeat="region in selected_brain_regions track by $index">
<input type="radio" name="radio_brain_regions_graphical_search_soma" value="{{region.id}}">
<b>{{region.name}}</b>
</label>
Check out jsFiddle

Custom directive to populate dynamic select box AngularJS

I've got the following controller that basically calls a http get service and assigns the data to a show_data scope variable
.controller('forms_controller', function($scope, Form) {
Form.get().then(function(data){
$scope.show_data = data;
});
});
The scope.show_data is then pushed to this view ..
<div ng-repeat="(key, value) in show_data | orderBy:'key' " >
<div ng-switch on="value.Type" >
<div ng-switch-when="attributes" >
<div ng-repeat="(key2, value2) in value | orderBy:'key' ">
<div ng-switch-when="Date" >
<label class="item item-input">
<span class="input-label">{{value2.Label}}</span>
<input identifier="{{value2.Identifier}}" type="date">
</label>
</div>
<div ng-switch-when="Select" >
<label class="item item-input item-select">
<div class="input-label">
{{value2.Label}}
</div>
<select codelist="{{value2.CodeList}}" identifier="{{value2.Identifier}}" >
</select>
</label>
</div>
</div>
</div>
</div>
Which basically checks the data based on the input type and spits out the different form elements based on the data. My problem is I am faced with is with the select box... Each select box has an id [codelist in this case] to the ng-options that should be displayed however, I'd first need to make another http get call to fetch this data before populating the ng-options ...
Please also note that there might be more then one select box per form.
I was thinking of using some kind've custom directive to achieve this?
Any help would be highly appreciated :)
Thank You
Your problem is that the server sends you an "incomplete" object. You need to do additional get requests to "complete" your object.
So this is what you should do: in your controller, iterate over your object and do the additional get-requests and store the results in something that you can call in your html with value2.items.
You don't have to wait with setting $scope.show_data untill all the data is fetched. Angular's two-way binding will synchronize the html as soon as the additional info is available.
Something like this should work.
var n = 0;
for (;n < data.length; n += 1) {
var values = data[n].value
var i = 0;
for (;i < values.length; i += 1) {
// GET based on values[i].CodeList
$http.get(...)
.success(function (data2) {
values[i].items = data2
// Retrieveable in HTML as value2.items
});
}
}

Dynamic ng-model name in AngularJS form

I have an AngularJS form where I'm using ng-repeat to build the fields of the form dynamically based on another selection. I'm trying to generate the model name dynamically and am running into problems.
<div class="form-group" ng-repeat="parameter in apiParameters">
<label for="{{parameter.paramName}}" class="col-sm-2 control-label">{{parameter.paramTitle}}</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="{{parameter.paramName}}" id="{{parameter.paramName}}" ng-model="formData.parameters.{{parameter.paramName}}" placeholder="{{parameter.paramTitle}}">
</div>
</div>
What I need is it to eval to something like ng-model="formData.parameters.fooId" or ng-model="formData.parameters.barId"
The above results in an error:
Error: [$parse:syntax] Syntax Error: Token '{' is an unexpected token at column 21 of the expression [formData.parameters.{{parameter.paramName}}] starting at [{{parameter.paramName}}].
In my controller I have:
$scope.formData = {};
$scope.formData = {
settings:
{
apiEndpoint: '',
method: 'get'
},
parameters: {}
};
I've also tried ng-model="formData.parameters.[parameter.paramName]" (based on this question How can I set a dynamic model name in AngularJS?), but that doesn't eval and fails to set the ng-model value. I'm not sure if what I'm trying to accomplish is even possible. I'm assuming I need to go through the controller to achieve what I want, but any help would be appreciated.
You just need to use hash key as model:
<div class="form-group" ng-repeat="parameter in apiParameters">
<label for="{{parameter.paramName}}" class="col-sm-2 control-label">{{parameter.paramTitle}}</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="{{parameter.paramName}}" id="{{parameter.paramName}}" ng-model="formData.parameters[parameter.paramName]" placeholder="{{parameter.paramTitle}}">
</div>
</div>
There is many other approaches, but this one are simpler than others.
I have tested this solution but it has a problem for my self. The problem is that the parameter "formData" is assigned to each iteration individually. In the other words if you insert a pre tag in every iteration you will see the value of each iteration individually and you cannot get all the formData in your controller after submitting the form.
For this I have found a very simple solution and it is the ng-init !!!!
Simply add this code to your form and before your repetitive tag. For the example of this question we will have:
<form ng-init="formData = []">
<div class="form-group" ng-repeat="parameter in apiParameters">
<label for="{{parameter.paramName}}" class="col-sm-2 control-label">{{parameter.paramTitle}}</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="{{parameter.paramName}}" id="{{parameter.paramName}}" ng-model="formData.parameters[parameter.paramName]" placeholder="{{parameter.paramTitle}}">
</div>
</div>
</form>

Resources