I'm working on this Angularjs table. When I delete a customer (clicking on remove) the specific customer goes away and that works fine :). But let's say I search for an specific customer like Alex typing Alex in the search box, then I want to delete it, but for some reason my removePerson function targets the first customer from the table. Please tell me what I'm doing wrong inside my removePerson funcion. Thanks a lot!!
and here's my code:
var App = angular.module('sortApp', ['ui.bootstrap'])
App.controller('mainController', function($scope, $modal, $log, $filter) {
$scope.sortType = 'id'; // set the default sort type
$scope.sortReverse = false; // set the default sort order
$scope.searchPerson = ''; // set the default search/filter term
// Array - List of People
$scope.People = [
{ id: 1, name: 'Mike', Lastname: 'White', age: 26 },
{ id: 2, name: 'Carl', Lastname: 'Barns', age: 41 },
{ id: 3, name: 'Deb', Lastname: 'McDonals',age: 78 },
{ id: 4, name: 'Tommy', Lastname: 'Humbs', age: 32 },
{ id: 5, name: 'Mary', Lastname: 'Browns', age: 18 },
{ id: 6, name: 'Alex', Lastname: 'Sams', age: 50 },
{ id: 7, name: 'Beto', Lastname: 'Burns', age: 27 }
];
/*
This function adds a new customer
*/
$scope.addPerson = function(){
var customer = {
name: $scope.name,
Lastname: $scope.Lastname,
age: $scope.age,
};
$scope.People.push(customer);
};
/*
This function removes a customer
*/
$scope.removePerson = function(index){
if(confirm("Are you sure to remove Customer")){
$scope.People.splice(index, 1);
}
};
$scope.openPopupScreen = function() {
var modalInstance = $modal.open({
template: '<div class="modal-header"> <a class="close" data- dismiss="modal" ng-click="cancel()"><i class="fa fa-times-circle-o" style="margin:10px;color:black;font-size:35px;"></i></a><h1>Add Customer</h1></div><div class="modal-body"> <form >' +
' <label class="col-sm-3 control-label no-padding-right ng-binding">NAME:</label><input style = "width:300px;"type="text" class="form-control ng-scope ng-pristine ng-valid" ng-model="person.name"></br>' +
' <label class="col-sm-3 control-label no-padding-right ng-binding">LASTNAME:</label><input style = "width:300px;" type="text" class="form-control ng-scope ng-pristine ng-valid" ng-model="person.Lastname"></br>' +
' <label class="col-sm-3 control-label no-padding-right ng-binding">AGE:</label><input style = "width:300px;" type="number"class="form-control ng-scope ng-pristine ng-valid" ng-model="person.age"></br>' +
' <button id = "myid" type="button" class="btn btn-success" ng-click="add()"><i class="ace-icon fa fa-check"></i>Add New Customer</button>' +
' <button type="reset" class="btn ">Clear</button>' +
'<div ng-hide = "error_name_message" id="Error_Message_name">'+
'<p>Please enter a name</p>'+
'</div>'+
'<div ng-hide = "error_lastname_message" id="Error_Message_Lastname">'+
'<p>Please enter a lastname</p>'+
'</div>'+
'<div ng-hide = "error_age_message" id="Error_Message_Age">'+
'<p>Please enter age</p>'+
'</div>'+
' </form>' +
'</div>' +
'<div class="modal-footer">' +
' <a data-dismiss="modal" aria-hidden="true" class="btn btn-primary" ng-click="cancel()">close</a>' +
'</div>',
controller: ModalInstanceCtrl
});
modalInstance.result.then(function (newPerson) {
$scope.People.push(newPerson);
});
};
var ModalInstanceCtrl = function($scope, $modalInstance) {
$scope.person = {name: '', Lastname: '', age: ''};
$scope.error_name_message = true;
$scope.error_lastname_message = true;
$scope.error_age_message = true;
$scope.ok = function() {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
};
$scope.add = function() {
//Pass newPerson to caller from main controller
if($scope.person.name === ""){
$scope.error_name_message= false;
$("#Error_Message_name").show().delay(1900).fadeOut(900); // don't leave error on screen for long
}
else if($scope.person.Lastname === ""){
$scope.error_lastname_message = false;
$("#Error_Message_Lastname").show().delay(1900).fadeOut(900); // don't leave error on screen for long
}
else if($scope.person.age === "" || $scope.person.age < 1){
$scope.error_age_message = false;
$("#Error_Message_Age").show().delay(1900).fadeOut(900); // don't leave error on screen for long
}
else{
$modalInstance.close($scope.person);
}
};
};
});
This is happening because you are passing the index key of the array of displayed element that is not the same of the original array. You can fix this in different ways. The one proposed here should work. Hope it helps.
Change your removePerson function into this:
$scope.removePerson = function(index){
if(confirm("Are you sure to remove Customer")){
angular.forEach($scope.People, function(value, key) {
if (value.id === index){
$scope.People.splice(key, 1);
}
});
}
};
And pass the id of the Person to the function from your HTML:
<button type="button" class="btn btn-danger fa fa-trash-o" ng-click="removePerson(people.id)"></button>
Related
I want to reset form fields after submitting the form my code is working fine but here for clearing input field I wrote like this all checkbox fields all checkbox fields I have to write.
$scope.appointmentForm = function() {
$scope.formData = {};
$http({
method: "POST",
url: "appointment_mail.php",
data: {
date: $scope.appt_date,
fname: $scope.fname,
lname: $scope.lname,
email: $scope.email,
notes: $scope.notes,
services: $scope.services,
category: $scope.category,
address: $scope.address,
timings: $scope.appt_timings,
phone: $scope.phone,
services: $scope.services,
category: $scope.category
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
data = response.data;
if (!data.success) {
// if not successful, bind errors to error variables
$scope.errorFname = data.errors.fname;
$scope.errorLname = data.errors.lname;
$scope.errorMail = data.errors.email;
$scope.errorPhone = data.errors.phone;
$scope.errorNotes = data.errors.notes;
$scope.errorAddress = data.errors.address;
$scope.messages = null;
} else {
// if successful, bind success message to message
$scope.fname = '';
$scope.lname = '';
$scope.email = '';
$scope.note = '';
$scope.address = '';
$scope.phone = '';
$scope.appointment_form.$setPristine();
$scope.messages = data.messages;
$timeout(function() {
// Loadind done here - Show message for 3 more seconds.
$timeout(function() {
$scope.messages = false;
}, 3000);
}, 2000);
//From here is there any other alternative way
$scope.category = {
"red": "",
"blue": "",
"green": "",
}
$scope.services = {
"abc": "",
"xyz": "",
}
$scope.appt_timings = "";
$scope.notes = "";
$("#iva_apptdate").datepicker('setDate', null);
}
}, function(error) {});
}
});
<div class="check-wrap">
<div class="cat">
<span class="checkbox">
<input type="checkbox" name="category" checked data-ng-model="iva_category.red">
<label>Red
</label>
</span>
</div>
<div class="cat">
<span class="checkbox">
<input type="checkbox" name="category" data-ng-model="category.blue">
<label>Blue
</label>
</span>
</div>
<div class="cat">
<span class="checkbox">
<input type="checkbox" name="category" data-ng-model="category.green">
<label>Green/label>
</span>
</div>
</div>
My question is there any alternate way to do this because here i have to write more code to clear checkbox input fields.Feel free to tell if anything wrong.
I am having an issue where ng-model is failing to bind to scope.
This section of my web app is set up like a wizard with three steps.
I want to include validation on the first step to prevent the user from reaching the second step if certain requirements are not met. However, in order to this, I need to use ng-model to bind firstName and secondName to the scope.
Here is my code so far, I've also included a plunker here:
wizard.html
<div id="wizard-container" ng-controller="WizardCtrl as vm">
<div id="wizard-step-container">
<ul class="nav nav-pills nav-justified">
<li ng-repeat="step in vm.steps" ng-class="{'active':step.step == vm.currentStep}"><a ng-click="vm.gotoStep(step.step)" href="">{{step.step}}. {{step.name}}</a></li>
</ul>
</div>
<div id="wizard-content-container">
<div ng-include src="vm.getStepTemplate()"></div>
</div>
<div id="wizard-navigation-container">
<div class="pull-right pull-right-padding">
<span class="btn-group">
<button ng-disabled="vm.currentStep <= 1" class="btn btn-default" name="previous" type="button" ng-click="vm.gotoStep(vm.currentStep - 1)"></i>Previous</button>
<button ng-disabled="vm.currentStep >= vm.steps.length" class="btn btn-primary" name="next" type="button" ng-click="vm.gotoStep(vm.currentStep + 1)">Next</button>
</span>
<button ng-disabled="vm.currentStep != vm.steps.length" class="btn btn-success" name="next" type="button" ng-click="vm.save()">Save</button>
</div>
</div>
</div>
step1.html
<div class="row">
<h3 class="text-center">Step 1: Please enter your full name</h3>
<br/>
<div class="col-md-6">
<input type="email" class="form-control" placeholder="First Name" ng-model="formData.firstName">
</div>
<div class="col-md-6">
<input type="email" class="form-control" placeholder="Last Name" ng-model="formData.lastName">
</div>
</div>
<br>
<div class="alert alert-danger" role="alert">
<strong>Oh snap!</strong> Please enter your full name.
</div>
wizard.js
angular.module('dingocvWebApp')
.controller('WizardCtrl', function ($scope, stub) {
// Wizard methods
var vm = this;
vm.currentStep = 1;
vm.formData = {};
vm.steps = [
{
step: 1,
name: 'Name',
template: 'views/wizard/step1.html'
},
{
step: 2,
name: 'Email',
template: 'views/wizard/step2.html'
},
{
step: 3,
name: 'Job Category',
template: 'views/wizard/step3.html'
},
];
vm.gotoStep = function(newStep) {
vm.currentStep = newStep;
console.log(vm.formData.firstName);
};
vm.getStepTemplate = function(){
for (var i = 0; i < vm.steps.length; i++) {
if (vm.currentStep === vm.steps[i].step) {
return vm.steps[i].template;
}
}
};
// Step 1
// Step 2
// Step 3
$scope.jobCategories = stub.getJobCategories();
// Yeoman defaults
this.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
});
I got it working. These were the tweaks:
script.js
I declared the formData object so that its interface is readily visible for us humans:
//Model
vm.currentStep = 1;
vm.formData = {firstName: null, lastName: null};
Each step gained a isReady() function that inspects the state of the vm object to decide if the user can interact with that step:
vm.steps = [
{
step: 1,
name: "First step",
template: "step1.html",
isReady: function() { return true; }
},
{
step: 2,
name: "Second step",
template: "step2.html",
isReady: function() { return vm.formData.firstName && vm.formData.lastName; }
},
{
step: 3,
name: "Third step",
template: "step3.html",
isReady: function() { return true; } // Didn't really care to write this one, sorry :)
},
];
Then, a vm.canGoForward() method was introduced. It checks for the readiness (and existence) of the next step in the chain:
vm.canGoForward = function() {
var res = true,
i,
nextStateIndex = vm.currentStep + 1;
if (nextStateIndex > vm.steps.length) {
return false;
}
for (i = 1; res && i <= nextStateIndex; i++) {
res = (res && vm.steps[i-1].isReady());
}
return !!res;
}
(If the above code looks a bit confusing, it might be so because of the 1-index baseness of the currentStep member; I'd prefer it to be 0-based...)
step1.html
The textboxes should indeed have the "vm." object identifier prepended to the ng-model values. This instructs the angular engine to get/set the appropriate values.
index.html
The forward button was changed so the ng-disabled directive would behave accordingly to the vm.canGoForward() function:
<button ng-disabled="!vm.canGoForward()" class="btn btn-primary" name="next" type="button" ng-click="vm.gotoStep(vm.currentStep + 1)">Next step <i class="fa fa-arrow-right"></i></button>
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
I have a dynamically changing orderBy filter in angular.
My HTML calls an updateOrder() method that takes a parameter 'date', 'value', 'seller.name', 'buyer.name', etc.:
<button type="button" ng-click="updateOrder('date')" class="btn btn-default navbar-btn">Date</button>
<button type="button" ng-click="updateOrder('value')" class="btn btn-default navbar-btn">Valuation</button>
<button type="button" ng-click="updateorder('seller.name')" class="btn btn-default navbar-btn">Alphabetical</button>
My updateOrder() method detects whether the order needs to be reversed and with what to order the list by:
$scope.order = 'date';
$scope.reverse = true;
let current = $scope.order;
$scope.updateOrder = function(order) {
console.log(order);
if(current === order) {
$scope.reverse = !$scope.reverse;
} else if(!$scope.reverse) {
$scope.reverse = true;
$scope.order = order;
current = order;
} else {
$scope.order = order;
current = order;
}
}
And then my ng-repeat div uses this order filter:
orderBy:order:reverse
For some reason, whenever I pass an argument with a dot (period), the filter fails and the order doesn't change. Due to other limitations, I would prefer not to change my database schema to not have subcategories (buyer.name, seller.name, etc.). Is there a way around this?
There's no issue with ordering by a dot-notated property. The issue is that you have ng-click="updateorder('seller.name')" and it should be ng-click="updateOrder('seller.name')". You have a lowercase "o" on your function call. Working sample:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.order = 'date';
$scope.reverse = true;
let current = $scope.order;
$scope.updateOrder = function(order) {
if (current === order) {
$scope.reverse = !$scope.reverse;
} else if (!$scope.reverse) {
$scope.reverse = true;
$scope.order = order;
current = order;
} else {
$scope.order = order;
current = order;
}
}
$scope.items = [{
date: new Date('2016-01-01'),
value: 100,
seller: {
name: 'Smith'
}
}, {
date: new Date('2016-05-01'),
value: 50,
seller: {
name: 'Smiley'
}
}, {
date: new Date('2016-03-01'),
value: 25,
seller: {
name: 'Jones'
}
}, {
date: new Date('2016-08-01'),
value: 500,
seller: {
name: 'Johnson'
}
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div>
<button type="button" ng-click="updateOrder('date')" class="btn btn-default navbar-btn">Date</button>
<button type="button" ng-click="updateOrder('value')" class="btn btn-default navbar-btn">Valuation</button>
<button type="button" ng-click="updateOrder('seller.name')" class="btn btn-default navbar-btn">Alphabetical</button>
</div>
<table>
<tr>
<th>Date</th>
<th>Value</th>
<th>Seller</th>
</tr>
<tr ng-repeat="item in items | orderBy:order:reverse">
<td>{{item.date | date: "M/d/yyyy"}}</td>
<td>{{item.value}}</td>
<td>{{item.seller.name}}</td>
</tr>
</table>
</div>
I am new to the MEAN and i am trying to make a simple CRUD application. I am getting an error of undefined on my _id and i do not understand why. This variable works withevery other function I call it in. Hopefully someone can help. I am getting the error on line 117 in my controller.js file
Here is the controller.js code for my application
todoApp.controller('TodoCtrl', function($rootScope, $scope, todosFactory) {
$scope.todos = [];
$scope.isEditable = [];
// get all Todos on Load
todosFactory.getTodos().then(function(data) {
$scope.todos = data.data;
});
// Save a Todo to the server
$scope.save = function($event) {
if ($event.which == 13 && $scope.todoInput) {
todosFactory.saveTodo({
"todo": $scope.todoInput,
"isCompleted": false
}).then(function(data) {
$scope.todos.push(data.data);
});
$scope.todoInput = '';
}
};
//update the status of the Todo
$scope.updateStatus = function($event, _id, i) {
var cbk = $event.target.checked;
var _t = $scope.todos[i];
todosFactory.updateTodo({
_id: _id,
isCompleted: cbk,
todo: _t.todo
}).then(function(data) {
if (data.data.updatedExisting) {
_t.isCompleted = cbk;
} else {
alert('Oops something went wrong!');
}
});
};
// Update the edited Todo
$scope.edit = function($event, i) {
if ($event.which == 13 && $event.target.value.trim()) {
var _t = $scope.todos[i];
todosFactory.updateTodo({
_id: _t._id,
todo: $event.target.value.trim(),
isCompleted: _t.isCompleted
}).then(function(data) {
if (data.data.updatedExisting) {
_t.todo = $event.target.value.trim();
$scope.isEditable[i] = false;
} else {
alert('Oops something went wrong!');
}
});
}
};
// Delete a Todo
$scope.delete = function(i) {
todosFactory.deleteTodo($scope.todos[i]._id).then(function(data) {
if (data.data) {
$scope.todos.splice(i, 1);
}
});
};
});
todoApp.controller('TodoCtrl', function($rootScope, $scope, todosFactory) {
$scope.todos = [];
$scope.isEditable = [];
// get all Todos on Load
todosFactory.getTodos().then(function(data) {
$scope.todos = data.data;
});
// Save a Todo to the server
$scope.save = function($event) {
if ($event.which == 13 && $scope.todoInput) {
todosFactory.saveTodo({
"todo": $scope.todoInput,
"isCompleted": false
}).then(function(data) {
$scope.todos.push(data.data);
});
$scope.todoInput = '';
}
};
//update the status of the Todo
$scope.updateStatus = function($event, _id, i) {
var cbk = $event.target.checked;
var _t = $scope.todos[i];
todosFactory.updateTodo({
_id: _id,
isCompleted: cbk,
todo: _t.todo
}).then(function(data) {
if (data.data.updatedExisting) {
_t.isCompleted = cbk;
} else {
alert('Oops something went wrong!');
}
});
};
// Update the edited Todo
$scope.edit = function($event, i) {
if ($event.which == 13 && $event.target.value.trim()) {
var _t = $scope.todos[i];
todosFactory.updateTodo({
_id: _t._id,
todo: $event.target.value.trim(),
isCompleted: _t.isCompleted
}).then(function(data) {
if (data.data.updatedExisting) {
_t.todo = $event.target.value.trim();
$scope.isEditable[i] = false;
} else {
alert('Oops something went wrong!');
}
});
}
};
// Delete a Todo
$scope.delete = function(i) {
todosFactory.deleteTodo($scope.todos[i]._id).then(function(data) {
if (data.data) {
$scope.todos.splice(i, 1);
}
});
};
});
Just is case the error is in either my factory.js code or html, I will include both.
Here is the factory.js code:
todoApp.factory('todosFactory', function($http){
var urlBase = '/api/todos';
var _todoService = {};
_todoService.getTodos = function(){
return $http.get(urlBase);
};
_todoService.saveTodo = function(todo){
return $http.post(urlBase, todo);
};
_todoService.updateTodo = function(todo) {
return $http.put(urlBase, todo);
};
_todoService.deleteTodo = function(id){
return $http.delete(urlBase + '/' + id);
};
return _todoService;
});
Here the html partial that uses the controller and factory:
<div class="container" ng-controller="TodoCtrl">
<div class="row col-md-12">
<div>
<input type="text" class="form-control input-lg" placeholder="Enter a todo" ng-keypress="save($event)" ng-model="todoInput">
</div>
</div>
<div class="row col-md-12 todos">
<div class="alert alert-info text-center" ng-hide="todos.length > 0">
<h3>Nothing Yet!</h3>
</div>
<div ng-repeat="todo in todos" class=" col-md-12 col-sm-12 col-xs-12" ng-class="todo.isCompleted ? 'strike' : ''">
<div class="col-md-1 col-sm-1 col-xs-1">
<input type="checkbox" ng-checked="todo.isCompleted" ng-click="updateStatus($event, todo._id, $index)">
</div>
<div class="col-md-8 col-sm-8 col-xs-8">
<span ng-show="!isEditable[$index]">{{todo.todo}}</span>
<input ng-show="isEditable[$index]" type="text" value="{{todo.todo}}" ng-keypress="edit($event)">
<input ng-show="isEditable[$index]" type="button" class="btn btn-warning" value="Cancel" ng-click="isEditable[$index] = false" />
</div>
<div class="col-md-3 col-sm-3 col-xs-3" >
<input type="button" class="btn btn-info" ng-disabled="todo.isCompleted" class="pull-right" value="edit" ng-click="isEditable[$index] = true" />
<input type="button" class="btn btn-danger" class="pull-right" value="Delete" ng- click="delete($index)" />
</div>
</div>
</div>
This line must be the cause of the issue:
<input ng-show="isEditable[$index]" type="text" value="{{todo.todo}}"
ng-keypress="edit($event)">
You forgot to pass the $index as the second parameter of the edit function. This should fix it:
<input ng-show="isEditable[$index]" type="text" value="{{todo.todo}}"
ng-keypress="edit($event, $index)">