I am trying to use a Factory Service function in my app to add a movie to my list. I have been able to remove a movie from the list, but I am having trouble figuring out why I can't add a movie to the current list.
var app = angular.module('application', []);
app.factory("MoviesService",[function(){
var movies = [
{title:"Avengers: Age of Ultron",rating:"PG-13",year:"2015"},
{title:"Ant-Man",rating:"PG-13",year:"2015"},
{title:"The Martian",rating:"PG-13",year:"2015"},
{title:"San Andreas",rating:"PG-13",year:"2015"},
{title:"Jurassic Park",rating:"PG-13",year:"2015"},
{title:"Dope",rating:"PG-13",year:"2015"}
];
var factory = {};
factory.getMovies = function(){
return movies;
};
factory.addMovie = function(){
var newMovie = {
title: movie.title,
rating: movie.rating,
year: movie.year
}
movies.push(newMovie);
};
factory.removeMovie = function(movie){
var index = movies.indexOf(movie);
movies.splice(index,1);
};
return factory;
}]);
app.controller('CustomerController',['$scope','MoviesService',function($scope,MoviesService){
$scope.movies = MoviesService.getMovies();
$scope.removeMovie = function(movie){
MoviesService.removeMovie();
};
$scope.addMovie = function(){
MoviesService.addMovie();
}
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app = "application">
<div class = "row">
<div class = "col-md-12" ng-controller = "CustomerController">
<table class="table">
<caption>Optional table caption.</caption>
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Year</th>
<th>Rating</th>
<th>Options</th>
</tr>
<tr>
<th>Add</th>
<th><input ng-model="movie.title" class="form-control"></th>
<th><input ng-model="movie.year" class="form-control"></th>
<th><input ng-model="movie.rating" class="form-control"></th>
<th>
<button class = "btn btn-success" ng-click="addMovie()"><span class = "glyphicon glyphicon-plus"></span></button>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat = "movie in movies">
<th scope="row">{{$index}}</th>
<td>{{movie.title}}</td>
<td>{{movie.year}}</td>
<td>{{movie.rating}}</td>
<td>
<button ng-click="removeMovie(movie)" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
First off, your addMovie function doesn't have access to movie, so it's probably throwing an error in the console. Change this:
factory.addMovie = function(){
to
factory.addMovie = function(movie) {
and change this:
$scope.addMovie = function(){
MoviesService.addMovie();
}
to:
$scope.addMovie = function() {
MoviesService.addMovie($scope.movie);
}
always pay attention to console errors. I made a working plunker of this in action:
http://plnkr.co/edit/AXNhovhKrW24FLOt9KGM?p=preview
Inside your addMovie function, you trying to add a movie from a movie variable that does not exist in this context. So you are probably getting an error there.
It looks like you're trying to do something like:
$scope.movie = {}; // add this
$scope.addMovie = addMovie; // modify to this
...
factory.addMovie = function(movie){ // add parameter movie
movies.push(movie);
};
...
give that a shot.
Related
Basically, i have a structure like this example
Every cell of last column needs to have this formula:
value[i][2] = value[i-1][2] + value[i][0] - value[i][1]
I'm actually having 2 problems. The first one comes when i just try to program the first row of the table. What's wrong with this extremely simple thing?
angular.module('calc', [])
.controller('cont', function($scope) {
$scope.addNumbers = function() {
var c = aCom[30][5];
var a = parseFloat($scope.entrata1);
var b = parseFloat($scope.uscita1);
return c+a-b;
}
});
considering entrata1 and uscita1 as they are value[0][0] and value[0][1].
But most important, how can I extend the formula to all other rows? Consider that every row except the first one is created dinamically with an appendChild()function to the body, do i have to use at every appended item the function setAttribute("ng-model","entrata")?
Thanks
I would suggest forget appendchild. Use ng-repeat and add rows adding to the scope
like this
angular.module('plunker', []).controller('tableCtrl', function($scope,$filter) {
$scope.rows = [{'a': 0,'u': 300},{'a': 0,'u': 150},{'a': 200,'u': 0},{'a': 0,'u': 300}];
$scope.rowscalc = function(val){
var total=0;
angular.forEach($scope.rows, function(values, key){
if(key<=val) total += values.u-values.a;});
return total;
};
$scope.addRowM = function(){
$scope.rows.push({'a': 0, 'u': 0});
};
});
<script src="//unpkg.com/angular/angular.js"></script>
<div ng-app="plunker" ng-controller="tableCtrl">
<table class="table">
<thead>
<tr>
<td class="dthead">A</td>
<td class="dthead">U</td>
<td class="dthead">Total</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows">
<td><input type="number" ng-model="row.a"/></td>
<td><input type="number" ng-model="row.u"/></td>
<td>{{rowscalc($index)}}</td>
</tr>
<tr>
<td colspan="3">
<button ng-click="addRowM()">Add Row</button>
</td>
</tr>
</tbody>
</table>
</div>
you can check in plunker
This is my template for component gamesGrid which I am using in index.html. Inside of this template I have a table on which i want to use ng-repeat but it is not working.
<div class="container">
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Platform</th>
<th>Score</th>
<th>Genre</th>
<th>Editor's Choice</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="detail in gamesDetails">
<td>{{detail.title}}</td>
</tr>
</tbody>
</table>
</div>
This is my component.js file
(function() {
'use strict';
angular.module('myApp').component('gamesGrid', {
templateUrl: './components/games-grid.view.html',
controller:'gamesGridController'
});
})();
This is my controller.js file
angular.module('myApp').controller('gamesGridController',function(gridDataFactory) {
this.$onInit = function() {
};
this.$postLink = function() {
this.gamesDetails = [];
gridDataFactory.fetchUserDetails().then(function(response) {
this.gamesDetails = response;
console.log(this.gamesDetails);
});
}
});
And this is my factory:
angular.module('myApp').factory('gridDataFactory', function($http) {
var gameDetails = [];
var obj = {};
obj.fetchUserDetails = function(){
return $http.get('http://starlord.hackerearth.com/gamesarena').then(function(response) {
gameDetails = response.data;
gameDetails.shift();
return gameDetails;
});
}
return obj;
});
As you can see i have ng-repeat in my template but it is not working and i am not able to see any data on view.
You are using this.gamesDetails so change your View to use controller syntax as follows.
<div class="container" ng-controller="gamesGridController as ctrl">
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Platform</th>
<th>Score</th>
<th>Genre</th>
<th>Editor's Choice</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="detail in ctrl.gamesDetails">
<td>{{detail.title}}</td>
</tr>
</tbody>
</table>
</div>
this.$postLink = function() {
this.gamesDetails = [];
gridDataFactory.fetchUserDetails().then(function(response) {
$scope.gamesDetails = response;
console.log(this.gamesDetails);
});
}
In this piece of code i see you have assigned this.gameDetails, which is not available in the scope. Use $scope.gameDetails to bind it to the view.
I am performing few operations like Add and Remove for my two JSON files data.
My requirement is that I need to add respective json names and show them in the table and then need to generate json object for the added/selected json names on button click. It's working fine(that I can able to show my json names on UI table and can get/generate the json data object for my selected/added json names data after button click).
But, the issue is: after generating the json object or after clicking of Send button, I can see that one row is adding extra on my UI table after clicking of Send button, I don't need this added extra row for my UI table, I need only whatever I added the json names only those should be displayed in my table after clicking of Send button. It's happening for my two json tables.(I have two Send buttons individually, one for First JSON and other for Second JSON).
I am not sure what's the wrong here ? Please help me that to display the selected json names in table on button click, that shouldn't include one extra row adding either using AngularJS or JavaScript. Thank you in advance ! Created Plnkr.
html:
<div>
<p>First Table:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Add</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in myFirstJson.Testing">
<td>{{getKey(value)}}</td>
<td><button ng-click="addFirst(value)">Add</button></td>
</tr>
</tbody>
</table>
<br> <br>
<table border="1" class="table">
<thead>
<tr>
<th>Name</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in firstJsonNames track by $index">
<td>{{getKey(value)}}</td>
<td><button ng-click="deleteFirst($index)">Delete</button></td>
</tr>
<tr ng-hide="firstJsonNames.length > 0">
<td colspan="3">
<p>No Names</p>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<table>
<tbody>
<tr>
<td>First Dropdown:<select ng-model="firstJsonNames.firstdropdown">
<option value="Test1">Test1</option>
<option value="Test2">Test2</option>
<option value="Test3">Test3</option>
</select><br />
</td>
</tr>
<tr>
<td>First Input:<input type="text" maxlength="50" size="50"
ng-model="firstJsonNames.firstInput" /> <br /></td>
</tr>
</tbody>
</table>
<br>
<br>
<button ng-click="generateFirstJson()">Send</button>
<br>
<br><p>Second Table:</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Add</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in mySecondJson.MyTest">
<td>{{value.Main.static.name}}</td>
<td><button ng-click="addSecond(value.Main.static.name)">Add</button></td>
</tr>
</tbody>
</table>
<br>
<br>
<table border="1" class="table">
<thead>
<tr>
<th>Name</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="name in secondJsonNames">
<td>{{name}}</td>
<td><button ng-click="deleteSecond(name)">Delete</button></td>
</tr>
<tr ng-hide="mySecondJson.MyTest.length">
<td colspan="3">
<p>No Names</p>
</td>
</tr>
</tbody>
</table>
<br>
<br>
<label>Enter Second Input Data:</label> <input
ng-model="secondJsonNames.SecondInput" placeholder="Input Text"><br>
<br>
<button ng-click="generateSecondJson()">Send</button>
<br>
<br>
</div>
app.js:
var app = angular.module('myApp', ['ui.router']);
app.controller('TestCtrl',function($scope, $http,$state,$stateParams,filterFilter,$rootScope) {
$rootScope.firstJsonNames = [];
$scope.secondJsonNames = [];
$scope.firstJsonNames.firstdropdown="Test1";
$scope.firstJsonNames.firstInput="1.5";
if($rootScope.myFirstJson == undefined)
{
$http.get('test.json').success(function(response) {
$rootScope.myFirstJson = response;
});
}
$scope.addFirst = function (name){
$rootScope.firstJsonNames.push(name);
console.log($rootScope.firstJsonNames);
};
$scope.deleteFirst = function (index){
$rootScope.firstJsonNames.splice(index,1);
};
$scope.getKey = function(item) {
return Object.keys(item)[0];
};
$scope.generateFirstJson = function(){
$rootScope.firstJsonNames.push({firstdropdown:$rootScope.firstJsonNames.firstdropdown, firstInput:$rootScope.firstJsonNames.firstInput});
console.log(angular.toJson($rootScope.firstJsonNames));
};
//second json
if($rootScope.mySecondJson == undefined)
{
$http.get('test1.json').success(function(response) {
$rootScope.mySecondJson = response;
});
}
$scope.addSecond = function (name){
$scope.secondJsonNames.push(name);
console.log($scope.secondJsonNames);
};
$scope.deleteSecond = function (name){
index = $scope.secondJsonNames.indexOf(name);
$scope.secondJsonNames.splice(index,1);
};
$scope.generateSecondJson = function(){
$scope.secondJsonNames.push({SecondInput:$scope.secondJsonNames.SecondInput});
console.log(angular.toJson($scope.secondJsonNames));
};
});
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'main.html',
controller: 'TestCtrl',
});
});
You are updating $rootScope.firstJsonNames and $scope.secondJsonNames, which are used in ng-repeat, So values are displaying in table. Use new variable for json creation.
For you are reference:
I have used
$scope.newjson2 = [];
$scope.newjson1 = [];
Plunker
http://plnkr.co/edit/r0VTaaT2rcfkiBNqyRmt?p=preview
JS:
var app = angular.module('myApp', ['ui.router']);
app.controller('TestCtrl',function($scope, $http,$state,$stateParams,filterFilter,$rootScope) {
$rootScope.firstJsonNames = [];
$scope.secondJsonNames = [];
$scope.firstJsonNames.firstdropdown="Test1";
$scope.firstJsonNames.firstInput="1.5";
$scope.newjson2 = [];
$scope.newjson1 = [];
if($rootScope.myFirstJson == undefined)
{
$http.get('test.json').success(function(response) {
$rootScope.myFirstJson = response;
});
}
$scope.addFirst = function (name){
$rootScope.firstJsonNames.push(name);
console.log($rootScope.firstJsonNames);
};
$scope.deleteFirst = function (index){
$rootScope.firstJsonNames.splice(index,1);
};
$scope.getKey = function(item) {
return Object.keys(item)[0];
};
$scope.generateFirstJson = function(){
$scope.newjson1 = angular.copy($rootScope.firstJsonNames);
$scope.newjson1.push({firstdropdown:$scope.firstJsonNames.firstdropdown, firstInput:$scope.firstJsonNames.firstInput});
console.log(angular.toJson( $scope.newjson1));
};
//second json
if($rootScope.mySecondJson == undefined)
{
$http.get('test1.json').success(function(response) {
$rootScope.mySecondJson = response;
});
}
$scope.addSecond = function (name){
$scope.secondJsonNames.push(name);
console.log($scope.secondJsonNames);
};
$scope.deleteSecond = function (name){
index = $scope.secondJsonNames.indexOf(name);
$scope.secondJsonNames.splice(index,1);
};
$scope.generateSecondJson = function(){
$scope.newjson2 = angular.copy($scope.secondJsonNames);
$scope.newjson2.push({SecondInput:$scope.secondJsonNames.SecondInput});
console.log(angular.toJson($scope.newjson2));
};
});
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'main.html',
controller: 'TestCtrl',
});
});
lets say i have a following code
var Names = ['test1','test2','test3'];
function ViewModel() {
var self = this;
self.RegistraionInfo = ko.observableArray(Names);
self.ChangeSelection = function (data,event) {
fnChangeSelection(data);
}
self.tableRows = ko.observableArray([]);
self.addNewRow = function () {
self.tableRows.push(new tableRow('', self));
}
self.addNewRow();
}
function tableRow(number, ownerViewModel) {
var self = this;
self.number = ko.observable(number);
self.remove = function () {
ownerViewModel.tableRows.destroy(this);
}
ko.applyBindings(new ViewModel());
and in html
<table >
<thead>
<tr class="active">
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="template:{name:'data-tableRow', foreach: tableRows}"></tbody>
<tfoot>
<tr>
<td >
<img id="btnAddRowProcedure1" src=#Url.Content("~/Content/img/plus.png") data-bind="click: addNewRow" />
</td>
</tr>
</tfoot>
</table>
<script id="data-tableRow" type="text/html">
<tr>
<td >
<img id="btnDelete" src=#Url.Content("~/Content/img/close.png") data-bind="click: function(){ $data.remove(); }" />
</td>
<td><select data-bind="options:$root.RegistraionInfo, , event:{ change:$root.ChangeSelection}"></select></td>
</tr>
</script>
what im trying to do here is when user clicks the #btnAddRowProcedure1 link a new tablerow will be added. and inside the table row there is a dropdown that is bound to the Names array.when the user changes the dropdown selection the ChangeSelection function is called.
The Problem is that i want knock out to send currently selected Names array element as Data but knockout sending the tableRow as data.Is there a way to overcome this problem.Im still not sure why this works like this.
UPDATE
After the #Roy J changes i was able to get this to work.but now i have stumbled upon another problem (sorry im a noob at knockout).I want to add a button when ever the user changes the selection so i have added the following code to the ViewModel
self.displayAddBtn = ko.computed(function () {
if (self.tableRows.length == 0)
{
return false;
}
return self.tableRows[self.tableRows.length-1].selected() !="";
}, self);
this code is only executed once.when the user changes the selection this is code is not executed.can some one tell me how i can make this work
You need to have a value binding on your select. That's where the new value will show up when your change function is called.
var Names = ['test1', 'test2', 'test3'];
function ViewModel() {
var self = this;
self.RegistraionInfo = ko.observableArray(Names);
self.ChangeSelection = function(data, event) {
console.debug("Changed to:", data.selected());
}
self.tableRows = ko.observableArray([]);
self.addNewRow = function() {
self.tableRows.push(new tableRow('', self));
}
self.addNewRow();
}
function tableRow(number, ownerViewModel) {
var self = this;
self.number = ko.observable(number);
self.remove = function() {
ownerViewModel.tableRows.destroy(this);
};
self.selected = ko.observable(); // new! bound to select
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<table>
<thead>
<tr class="active">
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody data-bind="template:{name:'data-tableRow', foreach: tableRows}"></tbody>
<tfoot>
<tr>
<td>
<img id="btnAddRowProcedure1" src=#Url.Content( "~/Content/img/plus.png") data-bind="click: addNewRow" />
</td>
</tr>
</tfoot>
</table>
<template id="data-tableRow">
<tr>
<td>
<img id="btnDelete" src=#Url.Content( "~/Content/img/close.png") data-bind="click: function(){ $data.remove(); }" />
</td>
<td>
<select data-bind="options:$root.RegistraionInfo, value:selected, event:{ change:$root.ChangeSelection}"></select>
</td>
</tr>
</template>
I am trying to use Angular Smart table. But I get this error message in the browser.
Error: [ng:areq] http://errors.angularjs.org/1.3.9/ng/areq?p0=safeCtrl&p1=not%20aNaNunction%2C%20got%20undefined
at Error (native)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:6:416
at Qb (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:19:417)
at sb (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:20:1)
at $get (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:76:95)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:57:257
at s (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:7:408)
at v (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:57:124)
at g (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:52:9)
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:51:118
This is my HTML
<div ng-controller="safeCtrl">
<button type="button" ng-click="addRandomItem(row)" class="btn btn-sm btn-success">
<i class="glyphicon glyphicon-plus">
</i> Add random item
</button>
<table st-table="displayedCollection" st-safe-src="rowCollection" class="table table-striped">
<thead>
<tr>
<th st-sort="firstName">first name</th>
<th st-sort="lastName">last name</th>
<th st-sort="birthDate">birth date</th>
<th st-sort="balance">balance</th>
</tr>
<tr>
<th colspan="5"><input st-search="" class="form-control" placeholder="global search ..." type="text" /></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in displayedCollection">
<td>{{row.firstName}}</td>
<td>{{row.lastName}}</td>
<td>{{row.birthDate}}</td>
<td>{{row.balance}}</td>
<td>
<button type="button" ng-click="removeItem(row)" class="btn btn-sm btn-danger">
<i class="glyphicon glyphicon-remove-circle">
</i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<script src="~/Scripts/CustomerView.js"></script>
and this is my Javascript:
angular.module('customerDetailTableApp', ['smart-table']).controller('safeCtrl', ['$scope', function($scope) {
var firstnames = ['Laurent', 'Blandine', 'Olivier', 'Max'];
var lastnames = ['Renard', 'Faivre', 'Frere', 'Eponge'];
var dates = ['1987-05-21', '1987-04-25', '1955-08-27', '1966-06-06'];
var id = 1;
function generateRandomItem(id) {
var firstname = firstnames[Math.floor(Math.random() * 3)];
var lastname = lastnames[Math.floor(Math.random() * 3)];
var birthdate = dates[Math.floor(Math.random() * 3)];
var balance = Math.floor(Math.random() * 2000);
return {
id: id,
firstName: firstname,
lastName: lastname,
birthDate: new Date(birthdate),
balance: balance
}
}
$scope.rowCollection = [];
for (id; id < 5; id++) {
$scope.rowCollection.push(generateRandomItem(id));
}
//copy the references (you could clone ie angular.copy but then have to go through a dirty checking for the matches)
$scope.displayedCollection = [].concat($scope.rowCollection);
//add to the real data holder
$scope.addRandomItem = function addRandomItem() {
$scope.rowCollection.push(generateRandomItem(id));
id++;
};
//remove to the real data holder
$scope.removeItem = function removeItem(row) {
var index = $scope.rowCollection.indexOf(row);
if (index !== -1) {
$scope.rowCollection.splice(index, 1);
}
}
}]);
I have tried with several ways, but couldn't find any solution. I have used ng-app inside html tag <html ng-app="myapp"> and controller in body tag <body ng-app="customerDetailTableApp">
You need to use only one ng-app into your view, and include(inject) your second dependency module into your first ng-app.
Multiple ng-app directives on a page
How many ng-App can be declared in in Angular JS?
angular.module('myapp', ['customerDetailTableApp']);