Create array of elements with same class - arrays

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

Related

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

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.

React onClick fires multiple times on load and doesn't contain callback function in component props

I believe I have two basic problems, which are probably connected. I'm trying to place an event handler with a callback function on a nested component. It didn't seem to be doing anything, so I replaced the callback function with an alert of JSON.stringify(this.props) to see if that would shed any light. It illuminated two problems: 1) my callback function was not in the props. 2) the alert popped up 2 times on page load, but did not pop up on click, like it was supposed to. I'm working through this React tutorial. Here are the relevant components:
var App = React.createClass({
mixins: [Catalyst.LinkedStateMixin],
getInitialState: function(){
return {
fishes: {},
order: {}
}
},
componentDidMount: function(){
base.syncState(this.props.params.storeId + '/fishes', {
context: this,
state: 'fishes'
});
var localStorageRef = localStorage.getItem('order-' + this.props.params.storeId);
if(localStorageRef){
this.setState({
order: JSON.parse(localStorageRef)
});
}
},
componentWillUpdate: function(nextProps, nextState){
localStorage.setItem('order-' + this.props.params.storeId, JSON.stringify(nextState.order));
},
loadSamples: function(){
this.setState({
fishes: require('./sample-fishes.js')
});
},
addFish: function(fish){
var timestamp = (new Date()).getTime();
this.state.fishes['fish-' + timestamp] = fish;
this.setState({ fishes: this.state.fishes });
},
removeFish: function(key){
if(confirm("Are you sure you want to remove this fish?")){
this.state.fishes[key] = null;
this.setState({ fishes: this.state.fishes });
}
},
addToOrder: function(key){
this.state.order[key] = this.state.order[key] + 1 || 1;
this.setState({ order: this.state.order });
},
// <<<<<<<< the function I'm having trouble with >>>>>>>>
removeFromOrder: function(key){
alert('hi');
delete this.state.order[key];
this.setState({ order: this.state.order });
},
renderFish(key){
return <Fish key={key} index={key} details={this.state.fishes[key]} addToOrder={this.addToOrder}/>
},
render: function(){
return (
<div className="catch-of-the-day">
<div className="menu">
<Header tagline="Fresh Seafood Market"/>
<ul className="list-of-fish">
{/*{ Object.keys(this.state.fishes).map(this.renderFish) }*/}
{ Object.keys(this.state.fishes).length > 0 ? Object.keys(this.state.fishes).map(this.renderFish) : <li>No Fishes!</li> }
</ul>
</div>
// <<<<<<<< I pass the function through to the Order component >>>>>>>>
<Order fishes={this.state.fishes} order={this.state.order} removeFromOrder={this.removeFromOrder}/>
<Inventory fishes={this.state.fishes} addFish={this.addFish} removeFish={this.removeFish} loadSamples={this.loadSamples} linkState={this.linkState}/>
</div>
)
}
});
var Order = React.createClass({
renderOrder: function(key){
var fish = this.props.fishes[key];
var count = this.props.order[key];
// <<<<<<<< the onClick I'm having trouble with >>>>>>>>
var removeButton = <button onCLick={this.props.removeFromOrder.bind(null, key)}>×</button>
// var removeButton = <button onCLick={alert(JSON.stringify(this.props))}>×</button>
if(!fish) {
return <li key={key}>Sorry, that fish is no longer available! {removeButton}</li>
// return <li key={key}>Sorry, that fish is no longer available!</li>
}
return (
<li key={key}>
{count}lbs
{" " + fish.name}
<span className="price">{helpers.formatPrice(count * fish.price)} {removeButton}</span>
{/*<span className="price">{helpers.formatPrice(count * fish.price)}</span>*/}
</li>
)
},
render: function(){
var orderIds = Object.keys(this.props.order);
var total = orderIds.reduce((prevTotal, key)=>{
var fish = this.props.fishes[key];
var count = this.props.order[key];
var isAvailable = fish && fish.status === 'available';
if(isAvailable) {
return prevTotal + (count * parseInt(fish.price) || 0);
}
return prevTotal;
}, 0);
return (
<div className="order-wrap">
<h2 className="order-title">Your Order</h2>
<ul className="order">
{ orderIds.length > 0 ? orderIds.map(this.renderOrder) : ""}
<li className="total">
<strong>Total:</strong>
{helpers.formatPrice(total)}
</li>
</ul>
</div>
)
}
});
The props for Order should include: the available fishes with all of their details, the current order with a fish id and quantity, and the removeFromOrder callback. When I explore the component in React dev tools, it has all of these things.
When I replace the removeFromOrder callback with an alert of the props, what happens is:
- on click, nothing
- on page refresh, two alerts pop up: the props in the first include the current order and an empty fishes array, the props in the second include the current order and the populated fishes array. Neither show the removeFromOrder callback function, which appears to be undefined from the perspective of the event listener.
On a potentially related note, when I explore the component in React dev tools and hover over a list item in the Order, I get the following error: TypeError: node.getBoundingClientRect is not a function. I'm not sure if this is part of my problem; if it's not, I'm not too concerned about it, since it only seems to pop up when I hover over the element in dev tools.
Thank you for reading this long thing, and any help would be much appreciated!
As #azium pointed out, the problem was a simple typo: onCLick={alert()} should instead be onClick={() => alert()}. Facepalm.

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);
}

Angularjs "this" is undefined in normal object

I am creating a quiz in angular and i use this code:
<ul>
<li ng-repeat="choice in choices" class="choices" ng-click="setSelection(choice)">{{choice}}</li>
</ul>
var choiceSelection = {
isSelected: false,
userAnswers: [],
setSelection: function(choice) {
this.userAnswers.push(choice);
console.log(this.userAnswers);
}
};
$scope.setSelection = choiceSelection.setSelection;
I want to store the users choice in the userAnswers array, but the this in setSelection is undefined and therefore this.userAnswers nor this.isSelected works. This code works in normal JS, I just tested it.
What's going on here?
You could bind the proper value for this to your setSelection function:
var choiceSelection = new function ( ) {
this.isSelected = false;
this.userAnswers = [];
this.setSelection = function(choice) {
this.userAnswers.push(choice);
console.log(this.userAnswers);
}.bind( this );
} ;
$scope.setSelection = choiceSelection.setSelection;

Print list in reverse order or put new items before the first

I'm starting with AngularJS and Firebase. I'm looking for the way to insert new items in a list (hosted in Firebase) at the top or print the last item of the list at the top.
The filter 'orderBy' from Angular doesn't work for me because it's a list.
My actual code for insert items:
var ref = new Firebase("https://[here is my instance].firebaseio.com/");
$scope.lineas = [];
angularFire(ref, $scope, "lineas");
$scope.agregarLinea = function() {
$scope.lineas.push({texto: $scope.linea});
$scope.linea = "";
};
And for list the items:
<ul class='lineas'>
<li ng-repeat="linea in lineas">
<span>{{linea.texto}}</span>
</li>
</ul>
Thank you in advance for your help.
when you use implicit databinding in angularfire, it returns an object which can't be used in an orderBy in angular. You could use angularFireCollection instead.
var ref = new Firebase("https://[here is my instance].firebaseio.com/");
$scope.lineas = [];
$scope.lineas = angularFireCollection(ref);
$scope.agregarLinea = function() {
$scope.lineas.add({texto: $scope.linea});
$scope.linea = "";
};
the id generated by firebase is based on a date, so can be used for sorting:
<ul class='lineas'>
<li ng-repeat="linea in lineas | orderBy:'-$id'">
<span>{{linea.$id}} - {{linea.texto}}</span>
</li>
</ul>
You can use JavaScript's splice() function to insert at the beginning of the array
$scope.lineas.splice(0, 0, {texto: $scope.linea});

Resources