Angular - Firebase - Repeating DIV ng-repeat duplicating new rows - angularjs

In running into a problem where I have a repeating DIV on my page, but I am getting duplicates when I add new rows. So for example if I have Row A and and Row B, and then I click "Add" to add a new row, I would like to see 3 rows. However I get 5 rows, Row A, Row B, then Row A, Row B and the new Row C.
The page initializes fine, will display only the 3 rows, but what am I doing wrong with the "Add" of new rows...It appears to be not refreshing as I would like?
Any help would be great!
Thanks!
My ng-repeat looks like this:
<div ng-repeat="infant in Infants" class="list card">
<h2>{{infant.name}} - {{infant.ID}}</h2>
<a class="item item-icon-left assertive" href="#"> <i class="icon ion-ios-analytics"></i> Last measurement 188mm / 190mm (size 5.5) </a>
</div>
The initialisation of Infants above is achieved with a global array:
$scope.Infants = [];
...
if (firebaseUser) {
//set the user and infant list variables
$log.log("Signed in as:", firebaseUser.uid);
var usersRef = firebase.database().ref('users');
loggedInUser = usersRef.child(firebaseUser.uid);
loggedInUser.on('value', snapshot => {
$log.log("UserDetails:", snapshot.val());
});
InfantList = loggedInUser.child('infantList');
InfantList.on('value', snapshot => {
$log.log("InfantDetails:", snapshot.val());
angular.forEach(snapshot.val(), function (value, key) {
$log.log("val", value);
$log.log("key", key);
$scope.Infants.push(value);
});
});
}
Then the function call when the ""Add" button is clicked looks like this:
$scope.AddProfile = function () {
// get the firebase location
var newInfantRef = firebase.database().ref('/users/' + firebaseUser.uid + '/infantList/');
// create the element
var newRef = newInfantRef.push();
//add attributes
var newItem = {
riskLevel: '1.0'
, ID: newRef.key
, name: "Reggie"
, gender: "M"
, DOB: "2015-02-01"
};
// Write the new infant.
var newInfant = {};
newInfant['/' + newRef.key + '/'] = newItem;
newInfantRef.update(newInfant);
}

In your InfantList.on() you are pushing again all values to the array when a new value is added.
To solve this try:
InfantList.on('child_added', snapshot => {
...your things...
}
This only push the new value to the array when the new value is added.

Related

Vue.js: Manipulate Array and post form with new data

In my Vue.js application I want to post form data to my Node.js/MongoDB Backend.
This is my source code: https://github.com/markusdanek/t2w-vue/blob/master/src/components/backend/JobEdit.vue
JSON for my job entry: http://t2w-api.herokuapp.com/jobs/591c09a55ba85d0400e5eb61
Relevant code for my question:
HTML:
<div class="row">
<input type='text'
:name="'qual'+index"
v-model="qualifications[index]">
<button #click.prevent="removeQualifiaction(index)">X</button>
</div>
Methods:
onChange(value, $event){
if (!this.job.xmlOnline)
this.job.xmlOnline = []
const index = this.job.xmlOnline.findIndex(v => v == value)
const checked = $event.target.checked
if (checked && index < 0)
this.job.xmlOnline.push(value)
if (!checked && index >= 0)
this.job.xmlOnline.splice(index, 1)
}
removeQualifiaction() {
this.qualifications.splice(this.qualifications.index, 1);
}
Sending the form data with submit button on form end:
editJob() {
let job = Object.assign({}, this.job);
job.qualifications = this.qualifications;
job.responsibility = this.responsibility;
this.$http.post('https://t2w-api.herokuapp.com/jobs/' + this.$route.params.id, job).then(response => {
console.log(response);
}, response => {
console.log(response);
});
}
My problems now:
When I edit a "Job", I have a list of "qualification items", that are input fields in my form.
Clicking the "delete" button results that the first input gets deleted, not the one I am clicking. Done with #thanksd answer.
How do I add a button and method to add a new input field and to append it to my job.qualifications?
In my JobAdd.vue implemented, to add a new entry to job.qualifications, like this:
<a #click.prevent="addQualification">+</a>
addQualification() {
this.qualification.push({ text: '' });
}
addJob() {
let job = Object.assign({}, this.job);
job.qualifications = this.qualification.map(q => q.text);
this.$http.post('https://t2w-api.herokuapp.com/jobs/', job).then(response => {....
Full source for my JobAdd.vue: https://github.com/markusdanek/t2w-vue/blob/master/src/components/backend/JobAdd.vue
this.qualification.push({ text: '' }); doesnt work obviously not in my JobEdit.vue when there are already strings in my job.qualifications.
Change your removeQualifiaction method to use the index being passed in:
removeQualifiaction(index) {
this.qualifications.splice(index, 1);
}

ngRepeat with custom index coming up blank

I'm using a large amount of arrays in a large form in my application. In order to make splicing out specific data from my datasets based on the user's selections, I've structured my arrays like this example:
var userList = [];
userList[user1.id] = user1;
userList[user2.id] = user2;
This lets me splice out specific elements without looping through the entire collection by using:
userList.splice(user1.id, 1);
However, when I try to make a list of Users in my HTML using an ng-repeat statement, it comes up blank. My HTML is:
<div data-ng-repeat="user in userList">{{user.name}}</div>
I suspect that ngRepeat uses 0,1,2.. by default and doesn't know how to handle my custom indexes. I've checked several sources but I can't really make sense of things. It did work when I added my users by simply pushing them into the array instead of assigning them to a specific index, so I know the rest of my code works fine.
Help? D:
EDIT:
The addition of a trackBy "track by user.id" didn't fix it.
Plunkr! http://plnkr.co/edit/8hANBvXAIplHsq0Ph6GX?p=preview
Your code isn't working because Array's indexes are zero-based meaning, they go from 0, 1, 2, ... n and you're trying to put alphanumeric indexes if you check the below code snippet the length of the array is zero.
var user1 = {
id: 'A1B2',
name: 'Pete'
};
var user2 = {
id: 'A2B3',
name: 'Jeff'
};
var userList = [];
userList[user1.id] = user1;
userList[user2.id] = user2;
console.log(userList);
console.log('length: ' + userList.length);
console.log(userList['A1B2']);
console.log(userList.A1B2); // behaving as JavaScript Object not array as property set using userList[user2.id] = user2;
So you need to set the data structure properly, you can set it as follows specifying the index of the array or by using the push function on the array to add a new item to the array.
var user1 = {
id: 'A1B2',
name: 'Pete'
};
var user2 = {
id: 'A2B3',
name: 'Jeff'
};
$scope.userList = [];
$scope.userList[0] = user1; // $scope.userList.push(user1);
$scope.userList[1] = user2; // $scope.userList.push(user2);
I suggest you change the collection name from userList to users it looks clean, you don't need to suffix a collection with the List keyword I think it looks untidy, just make the name plural.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
var pete = {
id: 'A1B2',
name: 'Pete'
};
var jeff = {
id: 'A2B3',
name: 'Jeff'
};
vm.users = [];
vm.users[0] = pete;
vm.users[1] = jeff;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="user in ctrl.users">
<span>{{user.id}}, {{user.name}}</span>
</div>
</div>
</div>
Do following
Controller:
$scope.userList = [];
$scope.userList.push(user1);
$scope.userList.push(user2);
View:
<tr ng-repeat="user in userList track by $index">
<td>{{user.id}}</td>
<td>{{user.name}}</td></tr>
change the id of each individual user to numeric from alpha-numeric as pointed by Adbul, array's indexes are number based
for eg:-
var user1 = {
id: 0, //Any numeric Value
name: 'Pete'
}
and then try $scope.userList[user1.id] = user1;
<div data-ng-repeat="user in userList">{{user.name}}</div>

Multiple dropdown selection in ag-grid (link Attached)

I need to have a column in ag-grid where i can select multiple values from dropdown. I just googled online to see if it is already implemented but i could find only one link.
https://gist.github.com/gaborsomogyi/00f46f3c0ee989b73c92
Can someone let me know how to implement it. show the full code as an example please.
Here is the code shared over there.
function agDropDownEditor(params, optionsName, optionsList) {
_.set(params.$scope, optionsName+'.optionsList', optionsList);
var html = '<span style="width:100%; display:inline-block" ng-show="!'+optionsName+'.editing" ng-click="'+optionsName+'.startEditing()">{{data.'+params.colDef.field+'}}</span> ' +
'<select style="width:100%" ng-blur="'+optionsName+'.editing=false" ng-change="'+optionsName+'.editing=false" ng-show="'+optionsName+'.editing" ng-options="item for item in '+optionsName+'.optionsList" ng-model="data.'+params.colDef.field+'">';
// we could return the html as a string, however we want to add a 'onfocus' listener, which is not possible in AngularJS
var domElement = document.createElement("span");
domElement.innerHTML = html;
_.set(params.$scope, optionsName+'.startEditing', function() {
_.set(params.$scope, optionsName+'.editing', true); // set to true, to show dropdown
// put this into $timeout, so it happens AFTER the digest cycle,
// otherwise the item we are trying to focus is not visible
$timeout(function () {
var select = domElement.querySelector('select');
select.focus();
}, 0);
});
return domElement;
}
Hope this helps, this is just a snippet of my code what i'm doing is I'm fetching from an array using map and then creating my object which is col and returning it and this will repeat till the last index of that array.
var col = {};
col.field = "fieldName";
col.headerName = "colName";
col.headerCellTemplate = function() {
var eCell = document.createElement('span');
eCell.field = obj.expr;
eCell.headerName = obj.colName;
eCell.innerHTML = "<select>"+"<option>"+
'Abc'+"</option>" +"<option>"+
'Xyz'+"</option>" +"</select>"
//$scope.dropDownTemplate;
var eselect = eCell.querySelector('select');
eselect.focus();
return eCell;
};
return col ;
}));

scope variable not updating with ng-change - angularjs

Seems like a simple problem though but finding it hard to fix.
There is a pagination component, that has a button & a dropdown. User can go to a page by either clicking the button or selecting that page number in dropdown.
The problem is, when I select a value in the dropdown, nothing happens. Because the scope variable doesnt change from the previous one.
aspx:
<div data-ng-app="app" data-ng-controller="ReportsCtrl">
<div id="paging-top">
<div>
<ul>
<li>
<select data-ng-model="SelectedPage" data-ng-change="ShowSelectedPage();"
data-ng-options="num for num in PageNumbers track by num">
</select>
</li>
<li data-ng-click="ShowNextPage();">Next</li>
</ul>
</div>
</div>
app.js
var app = angular.module("app", ["ngRoute"]);
ReportsCtrl.js
app.controller("ReportsCtrl", ["$scope","ReportsFactory",function ($scope,ReportsFactory) {
init();
var init = function () {
$scope.ShowReport(1);
}
$scope.ShowReport = function (pageNumber) {
GetUserResponsesReport(pageNumber);
}
function GetUserResponsesReport(pageNumber) {
$scope.UserResponsesReport = [];
var promise = ReportsFactory.GetReport();
promise.then(function (success) {
if (success.data != null && success.data != '') {
$scope.UserResponsesReport = success.data;
BindPageNumbers(50, pageNumber);
}
});
}
function BindPageNumbers(totalRows, selectedPage) {
$scope.PageNumbers = [];
for (var i = 1; i <= 5 ; i++) {
$scope.PageNumbers.push(i);
}
$scope.SelectedPage = selectedPage;
}
$scope.ShowSelectedPage = function () {
alert($scope.SelectedPage);
$scope.ShowReport($scope.SelectedPage);
}
$scope.ShowNextPage = function () {
$scope.SelectedPage = $scope.SelectedPage + 1;
$scope.ShowReport($scope.SelectedPage);
}
}]);
Say, the selected value in dropdown is 1. When I select 2 in the dropdown, the alert shows1. When Next is clicked, the dropdown selection changes to 2 as expected. Now, when I select 1 in the dropdown, the alert shows 2.
Tried to make a fiddle, but do not know how to do with a promise - http://jsfiddle.net/bpq5wxex/2/
With your OP SelectedPage is just primitive variable.
With every angular directive new scope is get created.
So,SelectedPage is not update outside the ng-repeat scope after drop-down is changed i.e. in parent scope which is your controller.
In order to do this,use Object variable instead of primitive data types as it update the value by reference having same memory location.
Try to define SelectedPage object in controller in this way.
$scope.objSelectedPage = {SelectedPage:''};
in HTML
<select data-ng-model="objSelectedPage.SelectedPage" data-ng-change="ShowSelectedPage();"
In ShowSelectedPage
$scope.ShowSelectedPage = function () {
console.log($scope.objSelectedPage.SelectedPage);
$scope.ShowReport($scope.objSelectedPage.SelectedPage);
}

Create array of elements with same class

Would this be an acceptable method of creating an array of elements having the same class, or is there something more efficient?
<ul>
<li class="show" id="all">All Posts</li>
<li class="show" id="user" data-user="7">My Posts</li>
<li class="show" id="follow">Following</li>
</ul>
$(document).ready(function() {
var newarr=[];
$("li").click(function(event) {
var name = event.target.className;
var newclass = 'choice';
$(this).addClass(newclass);
$(this).siblings().removeClass(newclass);
$('li[class~=' + newclass + ']').each(function(index) {
var thisid = $(this).attr('id');
newarr[index] = thisid;
})
$.each(newarr,function(index,value) {
//console.log(index + value);
})
});
});
I would use the map function to create the array:
var newarr = $('li[class~=' + newclass + ']').map(function(){
return $(this).attr('id');
});
im guessing newarr[index] = thisid; should just be newarr[] = thisid;.
but then again i dont even think i understand what you want to do.
why are you working from the .click handler?
on each click you set newclass to the clicked item and add it to the array. but you also remove the newclass from the siblings, so the previously clicked items will lose the newclass again... so in newarr only the last clicked item will have newclass

Resources