Angular error : Expected array but received: 0 - javascript

I'm getting this error when I open up a model partial:
<form action="" novalidate name="newGroupForm">
<div class="modal-body">
<div class="row">
<!-- SELECT THE NUMBER OF GROUPS YOU WANT TO CREATE -->
<label>Select number of groups</label>
<a class="btn" ng-click="newGroupCount = newGroupCount + 1" ng-disabled="newGroupCount == 10" ><i class="fa fa-plus-circle"></i></a>
<input class="groupCounter input-sm" ng-model="newGroupCount" type="number" min="1" max="10" disabled>
<a class="btn" ng-click="newGroupCount = newGroupCount - 1" ng-disabled="newGroupCount == 1"><i class="fa fa-minus-circle"></i></a>
</div>
<br>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Group Name</th>
<th>Group Description (optional)</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="i in getNumber(newGroupCount) track by $index">
<td>{{$index+1}}</td>
<td>
<input class= input-sm type="text" required="true" autofocus="true" placeholder="Group name" ng-model="groupData.title[$index]">
</td>
<td>
<input class="form-control input-sm" type="textarea" ng-model="groupData.desc[$index]" placeholder="Group Description">
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
<button class="btn btn-primary" type="submit" ng-click="submit()" ng-disabled="newGroupForm.$invalid">Create</button>
</div>
</form>
The modal controller looks like this:
spApp.controller('newGroupCtrl',
function newGroupCtrl($scope, $uibModalInstance, GroupService){
$scope.groupData = {
title: [],
desc: []
}
$scope.newGroupCount = 1;
$scope.getNumber = function(num) {
//console.log(num);
return new Array(num);
}
$scope.submit = function(){
$uibModalInstance.close($scope.groupData);
}
$scope.cancel = function (){
$uibModalInstance.dismiss('Cancelled group creation');
};
}
);
Every question I've seen refers to the use of filterbut I'm not using filter. The error repeats whenever I hit the increment button:
<a class="btn" ng-click="newGroupCount = newGroupCount + 1" ng-disabled="newGroupCount == 10" ><i class="fa fa-plus-circle"></i></a>

$scope.getNumber calls new Array(num), which will return an array of undefined values directly proportional to the value of newGroupCount.
For example:
new Array(5) // => [undefined, undefined, undefined, undefined, undefined]
Browsers don't handle that well, since it appears to be an empty array.
You're using ng-repeat in a way that it wasn't quite meant to be used. If I were you, I'd refactor to look something like this:
$scope.groups = [];
$scope.addGroup = function() {
// implement this, and use it in your button that increments the groups
$scope.groups.push(/* whatever */);
}
$scope.removeGroup = function() {
// implement this to remove a group
$scope.groups.splice(/* whatever */);
}
Then in your HTML:
<tr ng-repeat="group in groups">
<!-- display group info -->
</tr>
It may make your life easier here to work with angular (use it how it was intended) instead of fighting against how ng-repeat is meant to work.
The data is generally meant to be in the form of a collection (i.e. [{},{},{}]). Formatting it as such will make it easier for you. See the docs for ng-repeat.

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

submit AngularJS form with many dynamically created inputs

I am generating a set of three inputs per object in a JSON array. This is a simple mockup showing how I do this for two objects. I cannot seem to figure out how to grab all the inputs and submit it "the AngularJS way." Note that I chose to use ng-value over ng-model for the first two number inputs since the former collides with bootstrap in a really ugly way.
Is there some straightforward way to just grab all the input values and submit them, like you would do with a standard form?
HTML:
<form name="editForm" class="form-horizontal" ng-submit="saveEdit()">
<table class="edit_table table table-striped">
<thead>
<tr>
<th class="action_name_cell">Action</th>
<th class="float_cell">Warning Threshold</th>
<th class="float_cell">Error Threshold</th>
<th class="toggle_cell">Enabled</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in edit_rows()">
<td class="action_name_cell">test</td>
<td class="float_cell">
<div class="form-group">
<div class="col-sm-8">
<input type="number" class="form-control" name="{{row.threshold_id}}_warningDecimal"
placeholder="10.0" ng-value="row.warning"
ng-pattern="/^[0-9]+(\.[0-9]{1,2})?$/"
step="0.1" required />
</div>
</div>
</td>
<td class="float_cell">
<div class="form-group">
<div class="col-sm-8">
<input type="number" class="form-control" name="{{row.threshold_id}}_errorDecimal"
placeholder="10.0" ng-value="row.error"
ng-pattern="/^[0-9]+(\.[0-9]{1,2})?$/"
step="0.1" required />
</div>
</div>
</td>
<td class="toggle_cell">
<label></label><input name="{{row.threshold_id}}_enabled" type="checkbox" ng-checked="row.enabled" data-toggle="toggle">
</td>
</tr>
</tbody>
</table>
<div class="base_button_wrapper">
<button type="submit" class="btn btn-success">Save</button>
<button ng-click="cancelEdit()" type="button" class="btn btn-default">Cancel</button>
</div>
</form>
JS:
angular.module('rtmApp')
.controller('EditCtrl', ['$scope', '$location', '$window', '$timeout',
function ($scope, $location) {
// Change views and show the main view
$scope.cancelEdit = function() {
$location.path('/');
};
// Save, confirm success, then show the main again
$scope.saveEdit = function() {
console.log('Here is the data we are saving...');
// Let's see if we can see the data we are saving/submitting here:
console.log("? How do I get all the data ?");
$location.path('/');
};
var dummyEditJSON = [{
"threshold_id": 1,
"action_id": 1,
"action_name": "fast_preview",
"site_id": 1,
"site_name": "test_site",
"warning": 3.5,
"error": 5.0,
"enabled": true
},
{
"threshold_id": 2,
"action_id": 2,
"action_name": "bill_cgi",
"site_id": 1,
"site_name": "test_site",
"warning": 2.6,
"error": 4.2,
"enabled": false
}
];
$scope.edit_rows = function() {
return dummyEditJSON;
};
}]);
Your inputs have to be binded to an object. You do that with the ng-model directive. Take a look at this example: http://jsfiddle.net/krvom1ja/
$scope.data = {
a: 'a',
b: [{
v: 'b'
}, {
v: 'c'
}]
}
Assuming this is your form data, you keep it all in the same place. Then, when you submit the form, you simply grab $scope.data.
Also, your array of inputs is an actual array (look at key b)

Angular JS filter Search

I want to retain the selected check boxes as is even when I am
changing my search query. Initially I am posting some query in search
and selecting one of the resulted values, Now if I change my search
query, then New values will be my result. But I want to retain the
checkbox selected for the previous values...
`
//Demo of Searching and Sorting Table with AngularJS
var myApp = angular.module('myApp',[]);
myApp.controller('TableCtrl', ['$scope', function($scope) {
$scope.allItems = getDummyData();
$scope.resetAll = function()
{
$scope.filteredList = $scope.allItems ;
$scope.newEmpId = '';
$scope.newName = '';
$scope.newEmail = '';
$scope.searchText = '';
}
$scope.add = function()
{
$scope.allItems.push({EmpId : $scope.newEmpId, name : $scope.newName, Email:$scope.newEmail});
$scope.resetAll();
}
$scope.search = function()
{
$scope.filteredList = _.filter($scope.allItems,
function(item){
return searchUtil(item,$scope.searchText);
});
if($scope.searchText == '')
{
$scope.filteredList = $scope.allItems ;
}
}
$scope.resetAll();
}]);
/* Search Text in all 3 fields */
function searchUtil(item,toSearch)
{
/* Search Text in all 3 fields */
return ( item.name.toLowerCase().indexOf(toSearch.toLowerCase()) > -1 || item.Email.toLowerCase().indexOf(toSearch.toLowerCase()) > -1 || item.EmpId == toSearch
)
? true : false ;
}
/*Get Dummy Data for Example*/
function getDummyData()
{
return [
{EmpId:2, name:'Jitendra', Email: 'jz#gmail.com'},
{EmpId:1, name:'Minal', Email: 'amz#gmail.com'},
{EmpId:3, name:'Rudra', Email: 'ruz#gmail.com'}
];
}
.icon-search{margin-left:-25px;}
<br /> <br />
<div ng-app="myApp">
<div ng-controller="TableCtrl">
<div class="input-group">
<input class="form-control" ng-model="searchText" placeholder="Search" type="search" ng-change="search()" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</span>
</div>
<table class="table table-hover data-table sort display">
<thead>
<tr>
<th class="EmpId"> <a href="" ng-click="columnToOrder='EmpId';reverse=!reverse">EmpId
</a></th>
<th class="name"> Name </th>
<th class="Email"> Email </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in filteredList | orderBy:columnToOrder:reverse">
<td><input type="checkbox" name="test" />{{item.EmpId}}</td>
<td>{{item.name}}</td>
<td>{{item.Email}}</td>
</tr>
</tbody>
</table>
<div class="row">
<div class="col-xs-3">
<input type="text" ng-model="newEmpId" class="form-control" placeholder="EmpId">
</div>
<div class="col-xs-3">
<input type="text" ng-model="newName" class="form-control" placeholder="Name">
</div>
<div class="col-xs-4">
<input type="email" ng-model="newEmail" class="form-control" placeholder="Email">
</div>
<div class="col-xs-1">
<button ng-click="add()" type="button" class="btn btn-primary">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
</div>
</div> <!-- Ends Controller -->
</div>
`Fiddle
Try to add ng-model="item.selected" to your checkbox tag
<td><input ng-model="item.selected" type="checkbox" name="test" />{{item.EmpId}}</td>
Works for me, hope it helps.
Looks like this is happening because you are resetting the items here:
if($scope.searchText == '')
{
$scope.filteredList = $scope.allItems ;
}
and allItems doesn't tell anywhere if the checkbox needs to be selected on not. I would suggest you to update the code where you are creating the checkboxes, something like:
<td><input type="checkbox" name="test" ng-model=item.selected ng-checked=item.selected/>
Note that I have updated the item to have a 'selected' field which will tell if that item is selected or not(default could be false). While creating the checkbox I have linked the model using ng-model=item.selected
Updated fiddle at http://jsfiddle.net/3a3zD/194/

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.

Restangular does not PUT full object

I'm very new to it all so if I've made some massive oversights don't shout to hard.
I'm trying to update a table row using restangular. However it would seem like not all the object data is being set to the restapi. I have tested the restapi with POSTMAN so I know that works and I have also created new objects.
With google dev tools the PUT completes 200 OK but the Requested Payload only has the ID of the row. Actually if I attempt this on an existing row with data it clears all the data but the ID!
So here is what I have:
The HTML:
<div ng-controller="networksController">
<h1>{{title}}</h1>
<input type="text" ng-model="search" class="search-query" placeholder="Search">
<table class="table table-striped">
<thead>
<th>ID</th>
<th>Title</th>
<th>Reason</th>
<th>Actions</th>
<th>Requester</th>
<th>Verified</th>
<th></th>
</thead>
<tbody>
<tr ng-repeat="change in changes | filter:search">
<td>{{ change._id }}</td>
<td>
<div class="animate-show" ng-hide="editorEnabled">{{ change.title }}</div>
<div class="animate-show" ng-show="editorEnabled">
<input class="animate-input" type="text" ng-model="change.title" />
</div>
</td>
<td>
<div class="animate-show" ng-hide="editorEnabled">{{ change.reason }}</div>
<div class="animate-show" ng-show="editorEnabled">
<input class="animate-input" type="text" ng-model="change.reason" />
</div>
</td>
<td>
<div class="animate-show" ng-hide="editorEnabled">{{ change.actions }}</div>
<div class="animate-show" ng-show="editorEnabled">
<input class="animate-input " type="text" ng-model="change.actions" />
</div>
</td>
<td>
<div class="animate-show" ng-hide="editorEnabled">{{ change.requester }}</div>
<div class="animate-show" ng-show="editorEnabled">
<input class="animate-input" type="text" ng-model="change.requester" />
</div>
</td>
<td>
<div class="animate-show" ng-hide="editorEnabled">{{ change.verified }}</div>
<div class="animate-show" ng-show="editorEnabled">
<input class="animate-input" type="text" ng-model="change.verified" />
</div>
</td>
<td>
<input type="button" value="Edit" ng-hide="editorEnabled" ng-click="editorEnabled=!editorEnabled" />
<input type="button" value="Save" ng-show="editorEnabled" ng-click="editorEnabled=!editorEnabled; save(change)" />
<button ng-click="destroy(change)">Delete</button>
</td>
</tr>
</tbody>
</table>
The Main Controller:
var app = angular.module('richApp', ['ngResource', 'ngAnimate', 'restangular', 'xeditable'])
.config(function(RestangularProvider) {
RestangularProvider.setBaseUrl('api/');
});
The Page Controller:
app.controller('networksController', ['$scope', '$resource', 'Restangular', function($scope, $resource, Restangular) {
$scope.title = 'Network Control APP';
var baseChanges = Restangular.all('changes');
baseChanges.getList().then(function(changes) {
$scope.allChanges = changes;
});
$scope.changes = Restangular.all('changes').getList().$object;
$scope.destroy = function(change) {
Restangular.one("changes", change._id).remove();
};
$scope.save = function(change) {
Restangular.one("changes", change._id).put();
};
}]);
Ok so after 3 days of hunting high and low I finally find the answer. Mongo and restangular use different ID Keys. mongo uses _id whereas restangular uses id.
In order to correct this I needed to add the following
var app = angular.module('richApp', ['ngResource', 'ngAnimate', 'restangular', 'xeditable'])
.config(function(RestangularProvider) {
RestangularProvider.setBaseUrl('api/');
RestangularProvider.setRestangularFields({ //Added this
id: "_id" //Added this
}); //Added this
});
It's fair to say I also modified the following:
$scope.save = function(change) {
Restangular.one("changes", change._id).get().then(function(data) {
$scope.data = data;
});
var original = change;
$scope.data = Restangular.copy(original);
$scope.data.save();
};
I think you should use
$scope.save = function(change) {
change.put();
};

Categories

Resources