Removing from array has side-effects - javascript

I am making a form to create orders. The input fields are dynamic and can be added with a button.
Now after every row there is a delete button, which should delete the row.
For this this I made the delRow() function. It works because the row gets deleted, unfortunately the values of the rows underneath it are removed as well, but the input fields stay in place. I can't seem to figure out why.
Template:
<form>
<div class="form">
<table>
<tr ng-repeat="row in rows">
<td>
<input class="product" ng-model="row.product[$index]" placeholder="{{productPlaceholder}}" type="text">
</td>
<td>
<input ng-model="row.amount[$index]" type="number" min="0">
</td>
<td>
<button class="btn btn-primary btn-functionality btn-danger btn-del" ng-click="delRow($index)">x</input>
</td>
</tr>
</table>
<button class="btn btn-primary btn-success btn-add" ng-click="addRow()">+</button>
</div>
<div class="main-buttons">
<button class="btn btn-primary btn-lg btn-create" ng-click="createOrder()">Create</button>
<button class="btn btn-primary btn-lg" ng-click="cancelOrder()">Cancel</button>
</div>
</form>
Controller:
'use strict';
angular.module('myApp.orderNew', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/order/new', {
templateUrl: 'order-new/order-new.template.html',
controller: 'OrderNewCtrl'
});
}])
.controller('OrderNewCtrl', function($scope, $location, $http, $log) {
$scope.$log = $log;
$scope.message ="test";
$scope.rows = [{}];
$scope.counter = 1;
$scope.productPlaceholder = 'Product';
$scope.addRow = function() {
$scope.rows.push({});
$scope.counter++;
}
$scope.delRow = function(index) {
if ($scope.rows.length < 2) { return; }
$scope.rows.splice(index, 1);
}
$scope.cancelOrder = function() {
$location.path('/orders');
}
$scope.createOrder = function() {
var data = $scope.fields;
alert(data);
//$post('/path_to_server', obj);
}
$http.get('orders.json').then(function(data) {
$scope.orders = data;
});
});

Instead of:
<input ng-model="row.product[$index]" type="number" min="0">
You should do this:
<input ng-model="row.product" type="number" min="0">
Because you are deleting the rows the index reference is getting thrown off. Instead of using a index reference you can just just place the values directly to a attribute of the object.
I whipped up a working pen here:
http://codepen.io/nilestanner/pen/gmyBRo?editors=1011

Related

TypeError: $scope.lstLaptop.push is not a function

I'm trying to make a simple form for insert, delete, update using localStorage to store my data. When I click Add button, It shows an error
TypeError: $scope.lstLaptop.push is not a function.
I was back to my code and check syntax if I'm wrong, but I think my code was only 3 lines and look usual. Can you tell me what I was missing something or what the problem really was from?
Just ignored my other code and check my controller lapCreateUpdateCtrl please, I'm out of idea what I'm wrong.
HTML file:
<div class="container">
<table class="table table-hover">
<tr>
<th>Laptop Model</th>
<th>Price($)</th>
<th>Option</th>
</tr>
<tr ng-repeat = "laptops in lstLaptop track by $index">
<td><p ng-bind = laptops.model></p></td>
<td><p ng-bind = laptops.price></p></td>
<td><button type="button" ng-click="remove1($index)"
class="btn btn-danger btn-xs">
Delete
</button>
<button type="button" ng-click="edit1($index)"
class="btn btn-warning btn-xs">
Edit
</button>
<button type="button" ng-click="update1($index)"
class="btn btn-info btn-xs">
Update
</button>
</td>
</tr>
</table>
<button type="button" class="btn btn-success btn-sm"
ng-click="save()">
Save
</button>
</div>
</div>
</body>
app.JS file:
routerApp.controller('lapCreateUpdateCtrl', ["$scope", function($scope){
$scope.laptop = {};
$scope.lstLaptop = [];
function init(){
var strLaptop = window.localStorage.getItem("LAPTOP_KEY");
if(strLaptop){
$scope.lstLaptop = JSON.parse(strLaptop);
}
}
init();
$scope.add1 = function(){
$scope.lstLaptop.push($scope.laptop);
$scope.laptop = {};
}
$scope.remove1 = function(index){
$scope.lstLaptop.splice(index,1);
alert("Deleted!");
}
$scope.edit1 = function(index){
$scope.laptop = angular.copy($scope.lstLaptop[index]);
}
$scope.update1 = function(index){
$scope.lstLaptop.splice(index, 1, $scope.laptop);
$scope.laptop = {};
}
$scope.save=function(){
window.localStorage.setItem("LAPTOP_KEY", JSON.stringify($scope.lstLaptop));
}
}]);
I want content input from textbox
<input type="text" ng-model="laptop.model" id="model" name="model"
placeholder="Model" required />
<input type="number" ng-model="laptop.price" id="price" name="price"
placeholder="Price" required />
<button type="button" ng-click="add()">
Add Desktop
</button>
You have called init() and then inside that function, you have changed the $scope.lstLaptop to an object. When $scope.add1 will be called, it will throw an error as object does not have push function. It only works with Arrays.
I don't understand what you want to achieve, but you can do something like below. It will retain the lstLaptop as array
function init(){
var strLaptop = window.localStorage.getItem("LAPTOP_KEY");
if(strLaptop){
$scope.lstLaptop.push(JSON.parse(strLaptop));
}
}

Submitting form to file angularjs

I am trying to make a dynamic form for creating orders. With the add button it appends an input form so you can add more products per order when necessary.
Now I want to parse the form data to a JSON file, but how would I do that?
I've tried it with using field.product and field.amount as ng-models but it isn't working because when I type in a product in one row, the same text is in all the other rows as well.
<form>
<div class="form">
<table>
<tr ng-repeat="content in rows">
<td>
<input class="product" ng-model="field.product" placeholder="{{content.product}}" type="text">
</td>
<td>
<input ng-model="field.amount" type="number" min="0" value="1" type="text">
</td>
<td>
<button class="btn btn-primary btn-functionality btn-danger btn-del" ng-click="delRow($index)">x</input>
</td>
</tr>
</table>
<button class="btn btn-primary btn-success btn-add" ng-click="addRow()">+</button>
</div>
<div class="main-buttons">
<button class="btn btn-primary btn-lg btn-create" ng-click="createOrder()">Create</button>
<button class="btn btn-primary btn-lg" ng-click="cancelOrder()">Cancel</button>
</div>
</form>
<div style="text-align: center; font-size: 20px; border: 2px solid red; margin: 20px" ng-repeat="order in orders.data track by $index">
<div ng-repeat="product in order">
{{product.product}}
{{product.amount}}
</div>
</div>
Controller:
'use strict';
angular.module('myApp.orderNew', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/order/new', {
templateUrl: 'order-new/order-new.template.html',
controller: 'OrderNewCtrl'
});
}])
.controller('OrderNewCtrl', function($scope, $location, $http) {
$scope.field = {
amount: '1'
};
$scope.rows = [{
product: 'Product',
amount: 'Amount'
}];
$scope.counter = 1;
$scope.addRow = function() {
$scope.rows.push({
product: 'Product',
amount: 'Amount'
});
$scope.counter++;
}
$scope.delRow = function(row) {
if ($scope.rows.length < 2) { return; }
$scope.rows.splice(row, 1);
}
$scope.cancelOrder = function() {
$location.path('/orders');
}
$scope.createOrder = function() {
var data = $scope.fields;
alert(data);
//$post('/path_to_server', obj);
}
$http.get('orders.json').then(function(data) {
$scope.orders = data;
});
});
I'm not completely clear what you're asking, but it sounds like you want your models to each be unique for each repeated item in ng-repeat. If that's the case I would set the ng-model's to ng-model="field.product[$index]" and ng-model="field.amount[$index]"
make your question more clearly , but if you want submitform with ng-click , here is solution
$scope.field={}
$scope.createOrder = function(){
$http({
method:'post',
url:'yoururl',
data:$.param($scope.field),
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(onSuccess)
function onSuccess(response){
///handle when success
}
}

why Ng Repeat is not working if button invoked from a different form?

I have a html table that contains an ng repeat directive and two button.The first one will open a modal that contains a new form and let me create my user and then when i click save it will add it to the list.The second one is in the same original form and do the add a user.
What i did not understand why when i click on the first button which is in a different form i can not update the ng repeat however for the second one it's possible.
This is the code:
homepage.jsp
<body ng-app="myApp">
<div class="generic-container" ng-controller="UserController as ctrl">
<div id="createUserContent.jsp" ng-include="createUserContent"></div>
<table>
<tr>
<td>
<button type="button" class="btn btn-primary"
ng-click="ctrl.openCreateUser()">Create</button>
</td>
</tr>
</table>
<table class="table table-hover">
<thead>
<tr>
<th>ID.</th>
<th>Name</th>
<th>Address</th>
<th>Email</th>
<th width="20%"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="u in ctrl.users">
<td><span ng-bind="u.ssoId"></span></td>
<td><span ng-bind="u.firstName"></span></td>
<td><span ng-bind="u.lastName"></span></td>
<td><span ng-bind="u.email"></span></td>
</tr>
</tbody>
</table>
</div>
</body>
user_controller.js
'use strict';
App.controller('UserController', function ($scope, UserService, $window, $log, $uibModalStack,
$uibModal, $rootScope) {
var self = this;
self.users = [];
self.fetchAllUsers = function () {
console.log('----------Start Printing users----------');
for (var i = 0; i < self.users.length; i++) {
console.log('FirstName ' + self.users[i].firstName);
}
};
/**
this function will not work
**/
self.saveUser = function (user) {
self.users.push(user);
self.fetchAllUsers();
$log.log("saving user");
$uibModalStack.dismissAll();
};
/**
this function works fine
**/
self.addNewRow = function () {
var specialUser = {
id : 12,
firstName : 'john',
lastName: 'travolta',
homeAddress : {location:'chicago'},
email : 'trav#email.com'
};
self.users.push(specialUser);
$log.log("saving specialUser");
};
self.openCreateUser = function () {
var modalInstance = $uibModal.open({
animation : true,
templateUrl : 'createUserContent',
controller : 'UserController',
resolve : {
items : function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {
$log.info('Modal dismissed at: ' + new Date());
});
};
self.fetchAllUsers();
});
createUserContent.jsp
<form role="form" ng-controller="UserController as ctrl" >
<div class="form-group">
<label for="FirstName">FirstName</label> <input type="FirstName"
ng-model="ctrl.user.firstName" class="form-control"
id="FirstName" placeholder="Enter FirstName" /> <label
for="lastName">lastName</label> <input type="lastName"
class="form-control" id="lastName"
ng-model="ctrl.user.lastName" placeholder="Enter lastName" />
<label for="email">Email address</label> <input type="email"
ng-model="ctrl.user.email" class="form-control" id="email"
placeholder="Enter email" />
</div>
<div class="form-group">
<label for="homeAddressLocation">Home Address</label> <input class="form-control"
ng-model="ctrl.user.homeAddress.location" id="homeAddressLocation"
placeholder="homeAddressLocation" />
</div>
<div class="form-group">
<label for="SSOId">SSOId</label> <input class="form-control"
ng-model="ctrl.user.ssoId" id="SSOId" placeholder="SSOId" />
</div>
<button type="submit" class="btn btn-default"
ng-click="ctrl.saveUser(ctrl.user)">Save</button>
<button type="submit" class="btn btn-default">Cancel</button>
</form>
Because of your modal template can't access your UserController object and doesn't show error because you used in modal template same controller so reloaded as new Ctrl doesn't refer parent Ctrl.
However better to use different controller and pass parent controller object to modal controller and then modal body can use all parent object. so you should pass parent object to modal controller.
When you include createUserContent.jsp popup file in your main file then no need to use ng-controller="UserController as ctrl" in your modal template you used in modalInstance controller : 'Ctrl',
like:
var modalInstance = $uibModal.open({
templateUrl: 'createUserContent.jsp',
controller: 'ModalCtrl', // ModalCtrl for modal
controllerAs:'modal', // as modal so no need to use in modal template
size: 'lg',
resolve: {
items: function () {
return $scope.items;
},
parent: function(){ // pass self object as a parent to 'ModalCtrl'
return self;
}
}
and ModalCtrl like:
.controller('ModalCtrl', ['parent', function (parent) {
this.parent = parent;
}]);
here used ModalCtrl for modal as modal so you can access parent object like: modal.parent.user
template like:
<form role="form" >
<div class="form-group">
<label for="FirstName">FirstName</label> <input type="FirstName"
ng-model="modal.parent.user.firstName" class="form-control"
id="FirstName" placeholder="Enter FirstName" />
.....
....
<button type="submit" class="btn btn-default"
ng-click="modal.parent.saveUser(modal.parent.user)">Save</button>
<button type="submit" class="btn btn-default">Cancel</button>
</form>
More details Visit PLUNKER DEMO

update value not working

I'm trying to perform update on a value but ,the new value that am assigning to it bound to scope value but does not change ,when I edit ,it save with the original empty value
breakdown
$scope.showDepositUpdate = function(birthday) {
$scope.depositValue="one";
$scope.birthday = birthday;
$scope.action = 'deposit';
$scope.isAdd = false;
$scope.showUpdateModal = true;
};
$scope.updateDeposit = function() {
$scope.birthday.Name = $scope.depositValue;
StoreFactory.updateBirthday($scope.birthday);
$scope.depositValue='';
newValue =""
$scope.showUpdateModal = false;
};
but scope.depositValue does not update it according to value on the view , it always concat to "", here is my view
<form class="form-inline" ng-show="showUpdateModal">
<h2 class="title">{{ action }} Birthday</h2>
<div class="form-group">
<input type="text" class="form-control" ng-model="birthday.Name" placeholder="name" placeholder="Jane Doe">
</div>
<div class="form-group">
<input type="text" class="form-control" ng-model="depositvalue" placeholder="name" placeholder="deposit">
</div>
<button ng-click="updateDeposit()" class="btn btn-default btn-lg btn-rounded">Save</button>
</form>
<tr ng-repeat="birthday in birthdays">
<td>{{ birthday.Name }}</td>
<td>{{ birthday.Date }}</td>
<td> <button class="btn btn-info btn-sm btn-rounded" ng-click="showDepositUpdate(birthday)">deposit</button>
In your function $scope.updateDeposit you are stting up the value of the variable depositValue to "". $scope.depositValue='';. Maybe this is your problem?
I've done a snipet to show you that.
See if it is what you want.
var $scope = {};
var myApp = angular.module('myApp', []);
var StoreFactory = {
updateBirthday: function(){return true} // JUST A MOCKUP
};
myApp.controller('myCtrl', ['$scope',
function($scope) {
$scope.showDepositUpdate = function(birthday) {
$scope.depositValue = "one";
$scope.birthday = birthday;
$scope.action = 'deposit';
$scope.isAdd = false;
$scope.showUpdateModal = true;
};
$scope.updateDeposit = function() {
$scope.birthday.Name = $scope.depositValue;
StoreFactory.updateBirthday($scope.birthday);
$scope.depositValue = '';
newValue = ""
$scope.showUpdateModal = false;
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form class="form-inline" ng-show="showUpdateModal">
<h2 class="title">{{ action }} Birthday</h2>
<div class="form-group">
<input type="text" class="form-control" ng-model="birthday.Name" placeholder="Jane Doe">
</div>
<div class="form-group">
<input type="text" class="form-control" ng-model="depositvalue" placeholder="deposit">
</div>
<button ng-click="updateDeposit()" class="btn btn-default btn-lg btn-rounded">Save</button>
</form>
<tr ng-repeat="birthday in birthdays">
<td>{{ birthday.Name }}</td>
<td>{{ depositvalue }}</td>
<td>
<button class="btn btn-info btn-sm btn-rounded" ng-click="showDepositUpdate(birthday)">deposit</button>
</td>
</tr>
Did you try a console.log() of the value in your Factory? Whats the value there?
I once had such a problem and that was because (referred to your problem)
$scope.birthday.Name
is just a reference to $scope.depositValue and so you pass a reference to a function that is changed quite after function call ($scope.depositValue = '').
Would be good to know what StoreFactory.updateBirthday($scope.birthday); actually does.

add and delete json list inside ng-repeat

i want to create a page where someone adds 1 or more locations to a contact and right now i have something that looks like this.
<div class="input-append" ng-repeat="location in newPartner.partner_location">
<input class="input-large" type="text" ng-model="location">
<button class="btn" type="button" ng-click="delLocation1({{$index}})">- {{$index}}</button>
</div>
<div class="input-append">
<input class="input-large" type="text" ng-model="new_location">
<button class="btn btn-primary" type="button" ng-click="addLocation1()">+</button>
</div>
This is the HTML and the controller looks like this.
$scope.newPartner = {'partner_name':'newname','partner_location':['X','Y','Z']};
$scope.addLocation1 = function() {
$scope.newPartner.partner_location.push($scope.new_location);
$scope.new_location = "";
}
$scope.delLocation1 = function(id) {
$scope.newPartner.partner_location.splice(id, 1);
}
Now it works great on begin but if i delete some items and add some it suddenly bugs out and starts to delete the previous item instead the one i press - (minus) on.
Is there something i did wrong? Thank you in advance, Daniel!
First off remove {{}} from ng-click="delLocation1({{$index}})". It should be:
ng-click="delLocation1($index).
Second, I suggest you to add some basic debugger to see what happens with our model when we add new value: <pre>{{newPartner.partner_location|json}}</pre>
Third, I would change the model to:
$scope.newPartner = {
'partner_name': 'newname',
'partner_location': [{value:'X'}, {value:'Y'}, {value:'Z'}]
};
because, by this way: ['X','Y','Z'] we can't modify our data.
Demo Fiddle
Finally this is our fixed code:
HTML
<div ng-controller="fessCntrl">
<div ng-repeat="location in newPartner.partner_location">
<input class="input-large" type="text" ng-model="location.value">
<button class="btn" type="button" ng-click="delLocation1(newPartner.partner_location, $index)">{{$index}}</button>
</div>
<div class="input-append">
<input class="input-large" type="text" ng-model="new_location">
<button class="btn btn-primary" type="button" ng-click="addLocation1()">+</button>
</div>
<pre>{{newPartner.partner_location|json}}</pre>
</div>
JS
var fessmodule = angular.module('myModule', []);
fessmodule.controller('fessCntrl', function ($scope) {
$scope.new_location = "empty";
$scope.newPartner = {
'partner_name': 'newname',
'partner_location': [{value:'X'}, {value:'Y'}, {value:'Z'}]
};
$scope.addLocation1 = function () {
$scope.newPartner.partner_location.push({value:$scope.new_location});
$scope.new_location = "empty";
}
$scope.delLocation1 = function (locations, index) {
locations.splice(index, 1);
}
});
fessmodule.$inject = ['$scope'];

Categories

Resources