Angular - splice removes anything but the needed object from the array - javascript

I'm trying to remove contacts from my simple Phonebook app. However when I invoke the deletePerson function, I remove anything but the needed contact. Please show me my mistake guys.
My contacts partial:
<ul class="people-list">
<li showhideoptions ng-repeat="person in people | filter: search |
orderBy: 'name' | orderBy:'friend':true">
<h4>
<span ng-show="person.friend==true" class="icon-star icon-left"></span>
<span ng-show="person.friend==false" class="icon-user icon-left"></span>
{{person.name}}
<span ng-click="deletePerson($index)"
class="icon-remove pull-right"></span>
</h4>
</li>
</ul>
My main controller with factory:
var app = angular.module('contactList');
app.factory('simpleFactory', function(){
var people = [
{name: 'Collin', city: 'Omaha', friend: false},
{name: 'Alice', city: 'New York', friend: false},
{name: 'Pasha', city: 'Moscow', friend: true},
{name: 'Denis', city: 'St. Pete', friend: true}
];
var factory = {};
factory.getPeople = function() {
return people;
};
return factory;
});
app.controller('MainController', function ($scope, simpleFactory) {
$scope.people = [];
init();
function init() {
$scope.people = simpleFactory.getPeople();
}
$scope.addPerson = function() {
$scope.people.push(
{ name: $scope.newPerson.name,
city: $scope.newPerson.city,
friend: false
});
};
$scope.deletePerson = function($index) {
$scope.people.splice($index, 1);
}
});
UPD
I now understand that the filter
| filter: search | orderBy: 'name' | orderBy:'friend':true"
Makes my deleting process go crazy. If anyone could advise me on how to tackle this problem, I'd appreciate that!

You can delete using the item itself, something like
HTML
<span ng-click="deletePerson(person)"
class="icon-remove pull-right">
</span>
JS
$scope.deletePerson = function(item) {
$scope.people.splice($scope.people.indexOf(item), 1);
}

Related

How to keep a total between AngularJS Components in ngRepeat

Here's the problem - a limited number of licences can be assigned to users, when the available number is 0 no more can be assigned and other buttons will be disabled. Licences can removed and reassigned.
The list of users is in an ngRepeat loop, and the assign / remove licence function is in a component. When I click the assign / remove button it updates itself and the total, but the button in other components don't update until the next click.
Here's the full code of what I have so far: http://plnkr.co/edit/T4soR8qpSAzY0cANknsE?p=preview
The HTML:
<body ng-controller="RootController as root">
<pre>qty: {{ root.qtyAvailable }} / {{ root.qtyMax }}</pre>
<div ng-repeat="user in root.users | orderBy: 'firstname' ">
{{ user.firstname }}
<assign
has-licence="user.hasLicence"
reassignable="user.reassignable"
qty="root.qtyAvailable"
qty-max="root.qtyMax"
></assign>
</div>
</body>
The controller and component:
.controller('RootController', function() {
this.qtyMax = 2;
this.qtyAvailable = 1;
this.users = [
{firstname: 'john', hasLicence: false, reassignable: true},
{firstname: 'jane', hasLicence: false, reassignable: true},
{firstname: 'joey', hasLicence: false, reassignable: true},
{firstname: 'bob', hasLicence: true, reassignable: true},
];
})
.component('assign', {
template: `<button ng-click="$ctrl.click($ctrl.hasLicence)">{{ $ctrl.text }}</button>`,
controller: function() {
this.text = '';
// set the button text
this.buttonText = function() {
if(this.hasLicence) {
this.text = 'remove';
}
else if(!this.hasLicence && this.reassignable && this.qty>0) {
this.text = 'assign';
}
else {
this.text = '-'; // eg button disabled
}
}
this.buttonText();
// click function
this.click = function(licence) {
if(licence === true) {
this.hasLicence = false;
this.qty++
}
else if(this.qty>0) {
this.hasLicence = true;
this.qty--
}
this.buttonText(this.hasLicence);
console.log(this.qty)
}
},
bindings: {
hasLicence: '<',
reassignable: '<', // not relevant for this demo
qty: '=',
qtyMax: '<'
}
});
Something like this:
template: `<button ng-disabled="$ctrl.qty <= 0 && !$ctrl.hasLicence" ng-click="$ctrl.click($ctrl.hasLicence)">{{ $ctrl.text }}</button><span ng-if="$ctrl.qty <= 0 && !$ctrl.hasLicence">No licenses are free</span>`
Using extendend syntax : ng-disabled="$ctrl.qty <= 0 && !$ctrl.hasLicence" for only disabling the buttons to add a license when the 'free licenses' var is <= 0.
Updated Plunkr
If you want to execute the buttonText() function specifically you can add a watch on the qty variable and execute it:
.component('assign', {
template: `<button ng-click="$ctrl.click($ctrl.hasLicence)">{{ $ctrl.text }}</button>`,
controller: function($scope) { // $scope injection here
...
// Note: you can use arrow functions to omit the assignment of context
var me = this;
$scope.$watch(function() {
return me.qty;
}, function() {
me.buttonText();
});
},
bindings: {
...
}
});
Updated plunker here: plunkr

Use the value of a variable to find an item in array

I am still having trouble using the var to identify the object in the array. Here is what I have right now:
in controller:
$scope.allbooks=[
{book1={title:"Eat Pray Love", price:"$3.99"},
{book2={title:"DaVinci Code", price:"$7.99"}}
]
$scope.pick=function(name){
$rootScope.choice = name;
}
in html template
<ion-item ng-click="pick(book1)">
{{allbooks.choice[0].title}} <----This does not work
Used an alert to make sure choice=book1 which it does...I don't know what I am doing wrong
PLEASE HELP :(
[
{book1={title:"Eat Pray Love", price:"$3.99"},
{book2={title:"DaVinci Code", price:"$7.99"}}
]
is not valid javascript. If you are trying to define an object literal you'll need to adjust your syntax a bit:
$scope.allbooks = [
{title:"Eat Pray Love", price:"$3.99"},
{title:"DaVinci Code", price:"$7.99"}
]
Now you can access each book:
$scope.allbooks[0]; // returns first book
$scope.allbooks[1]; // returns second book
in controller:
$scope.allbooks=[
{book1:{title:"Eat Pray Love", price:"$3.99"}},
{book2:{title:"DaVinci Code", price:"$7.99"}}
];
$scope.choice = {}; //a variable to store your choice
$scope.pick=function(name){
$scope.choice = $scope.allbooks[name];
}
in html template
<ion-item ng-click="pick('book1')"> <!-- pass book1 as string -->
{{choice.title}}
angular.module("app", [])
.controller("main", function($scope) {
$scope.allbooks = {
book1: {
title: "Eat Pray Love",
price: "$3.99"
},
book2: {
title: "DaVinci Code",
price: "$7.99"
}
};
$scope.choice = {}; //a variable to store your choice
$scope.pick = function(name) {
$scope.choice = $scope.allbooks[name];
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="main">
<button ng-click="pick('book1')">Test</button>
<!-- pass book1 as string -->
{{choice.title}}
</div>

Filtering an ng-repeat based on multiple values in angular

This is difficult to phrase but:
I have 1 collection called users.
Every user has 3 properies: id, name, skill.
{
_id: 1,
name: 'frank young',
skill: 'java'
},
I have 1 form collects search results upon pressing enter.
<form ng-submit="pushToNewArry(searchTerm)">
<input type="text" ng-model="searchTerm" />
<input type="submit">
</form>
this is not the best way to do this
$scope.newUsers = [];
$scope.pushToNewArry = function(msg) {
$scope.trackedUsers.push(msg);
$scope.searchTerm = '';
};
Question:
How do I create a filter that will run over multiple search terms and create a list proper matches based on the users collections vs inputed values.
<ol ng-repeat = "user in users | filter: trackedUsers">
<li class="names"><span>{{$index}}. </span>{{user.name}}</li>
<li class="skills">{{user.skill}}</li>
</ol>
Upon submission, the user input will be saved and create a new array of users based on inputed values of search. therefore, multiple matching values.
Updated:
JSFiddle
not excatly the same as example above because I keep playing with it.
You mean like this jsfriddle
updated fiddle
updated fiddle2
<div>{{listSearchTerms | json}}</div>
<form ng-submit="saveSearchTerm()">
<input type="text" ng-model="searchTerm" />
<input type="submit">
</form>
<ol ng-repeat = "user in users | filter:filterSearch(searchTerm)">
<li class="names"><span>{{$index}}. </span>{{user.name}}</li>
<li class="skills">{{user.skill}}</li>
</ol>
Javascript
var app = angular.module('app', []);
//App.directive('myDirective', function() {});
//App.factory('myService', function() {});
app.controller('MainCtrl', function ($scope) {
$scope.users = [
{
_id: 1,
name: 'frank young',
skill: 'java'
},
{
name: 'jeff qua',
skill: 'javascript'
},
{
name: 'frank yang',
skill: 'python'
},
{
name: 'ethan nam',
skill: 'python'
},
{
name: 'ethan nam',
skill: 'javascript'
},
];
$scope.searchTerm = "";
$scope.listSearchTerms = [];
$scope.filterSearch = function (terms) {
return function (item) {
return terms.length < 1 ? true :
terms.reduce(function (lastresult, term) {
return lastresult + (item.name.indexOf(term) > -1 || item.skill.indexOf(term) > -1);
}, 0) > 0;
}
};
$scope.saveSearchTerm = function () {
$scope.listSearchTerms.push($scope.searchTerm);
$scope.searchTerm = "";
}
});

Angular, hide parent when there are no child-elements with nested ng-repeat's

I know there are some posts on the subject, but I could get this specific example working,
because of the nesting:
I have a FAQ with 3 levels of nesting, rendered by ng-repeats,
I want to hide the Category and the Subcategory if the query returns no questions.
I made a Fiddle, can anyone help me get this to work?
http://jsfiddle.net/Lp02huqm/
Thanks!
HTML
<div ng-app="faqApp" ng-controller="FaqController">
<input ng-model="query" type="text">
<ul class="collapse-list">
<li ng-repeat="category in faq | filter:matchEveryWord() | orderBy:rankOrder">
<h3>{{category.category}}</h3>
<div>
<ul>
<li ng-repeat="subcategory in category.subcategories | filter:matchEveryWord()">
<h3>{{subcategory.subcategory}}</h3>
<div>
<ul>
<li ng-repeat="question in subcategory.questions | filter:matchEveryWord()">
<h3>{{question.question}}</h3>
<div>{{question.answer}}</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
Javascript:
var faqApp = angular.module('faqApp', []);
faqApp.controller('FaqController', ['$scope' , function ($scope){
$scope.faq = [
{category: 'Category1',
rank:2,
subcategories: [
{subcategory: 'Subcategory1',
questions: [
{
question: 'this is the first question',
answer: 'this is the answer on the first question'
},
{
question: 'this is the second question',
answer: 'this is the answer on the second question'
}
]
},
{subcategory: 'Subcategory2',
questions: [
{
question: 'this is the first question of the second subcategory',
answer: 'this is the answer on the first question of the second subcategory'
},
{
question: 'this is the second question',
answer: 'this is the answer on the second question'
}
]
}
]
},
{category: 'Category2',
rank:1,
subcategories: [
{subcategory: 'Subcategory3',
questions: [
{
question: 'Apple',
answer: 'the answer to apple'
},
{
question: 'Banana',
answer: 'the answer to banana'
}
]
},
{subcategory: 'Subcategory4',
questions: [
{
question: 'this is the first question of subcategory 4',
answer: 'this is the answer on the first question of subcategory 4'
}
]
}
]
}
];
$scope.rankOrder = 'rank';
$scope.query = '';
$scope.matchEveryWord = function() {
return function( item ) {
var string = JSON.stringify(item).toLowerCase();
var words = $scope.query.toLowerCase();
if(words){
var filterBy = words.split(/\s+/);
if(!filterBy.length){
return true;
}
} else {
return true;
}
return filterBy.every(function (word){
var exists = string.indexOf(word);
if(exists !== -1){
return true;
}
});
};
};
}]);
In your li element, add ng-show to show subcategories only if questions are present. Something like:-
<li ng-repeat="subcategory in category.subcategories | filter:matchEveryWord()" ng-show="areQuestionsPresent(subcategory)">
Now, in your controller, define a method areQuestionsPresent, that will evaluate whether there are any questions or not:-
$scope.areQuestionsPresent = function(category) {
return category.questions.length > 0;
}
I am in a hurry otherwise would have given some more details. Hope this helps.
You can try nesting the two loops together, and only displaying the category title once.
That will change your current setup a bit (you can place your list back, I used a div because it was quicker for me), but it works:
<div ng-repeat="subcategory in category.subcategories | filter:matchEveryWord()">
<ul>
<li ng-repeat="question in subcategory.questions | filter:matchEveryWord()">
<h3 ng-if="$first">{{subcategory.subcategory}}</h3>
<h4 class="bullet">{{question.question}}</h4>
<div>{{question.answer}}</div>
</li>
</ul>
</div>
I updated your fiddle here: http://jsfiddle.net/Lp02huqm/5/

AngularJS | orderBy filter not updated dynamically

I'm having trouble with the orderBy filter in AngularJS. Here's my setup:
<li ng-repeat="item in listItems.data | orderBy:order">
<a ng-click="getRelated(item._id)">{{ item.title }}</a>
</li>
Part of the controller:
$scope.order = 'year';
$scope.listItems = $http.post($scope.url, {'filterType': 'abc', 'letter': $scope.params.letter});
$scope.setOrder = function(order) {
$scope.order = order;
}
And finally the "switches" I would like to use for ordering the data
<span class="sort--title">Sort by</span>
<a ng-class="{true:'selected', false:''}[order=='title']" href="" ng-click="setOrder('title')" class="sort--attribute">Title</a>
<a ng-class="{true:'selected', false:''}[order=='year']" href="" ng-click="setOrder('year')" class="sort--attribute">Year</a>
<a ng-class="{true:'selected', false:''}[order=='length']" href="" ng-click="setOrder('length')" class="sort--attribute">Length</a>
<a ng-class="{true:'selected', false:''}[order=='date_added']" href="" ng-click="setOrder('date_added')" class="sort--attribute">Date Added</a>
When I click the buttons, the list is not being re-ordered.
When I manually change the initial $scope.order value, the list is ordered by the property. Also ng-class is updated correctly. I'm obviously missing out something!
I don't think your idea is wrong. It does work. Here is the working plunker.
You must have something wrong somewhere else.
app.js
var app = angular.module('ngApp', []);
app.controller('MainCtrl', ['$scope', function ($scope) {
'use strict';
$scope.friends = [
{name: 'John', phone: '555-1276'},
{name: 'Mary', phone: '800-BIG-MARY'},
{name: 'Mike', phone: '555-4321'},
{name: 'Adam', phone: '555-5678'},
{name: 'Julie', phone: '555-8765'}
];
$scope.setOrder = function (order) {
$scope.order = order;
};
}]);
main html
<ul class="nav nav-pills">
<li ng-class="{'active': order=='name'}">name</li>
<li ng-class="{'active': order=='phone'}">phone</li>
</ul>
<ul>
<li data-ng-repeat="friend in friends|orderBy:order">
<span class="name">{{friend.name}}</span>
<span class="phone">{{friend.phone}}</span>
</li>
</ul>
I know its an old question but anyone else having the same issue might find this useful.
I had the same issue. Clicks to anchor were reloading the page and hence, the order was being set to default whenever you click any table header. This also explains why not setting the order to a default globally fixed it for you.
I replaced my anchor with a span element and it worked fine.

Categories

Resources