MEAN stack editing a post - angularjs

So I am working on my very first MEAN stack app and I am using using type script.
I have my post working just fine, but my edit post is not working. Since this is my first app I am not quite sure why. The error says that my parameters for my post are undefined. I hope one of you lovely people can help me out. I've avoided asking for help for a long time because I am sure its a stupid error.
controllers.ts
http://pastebin.com/bhXT5bLz
app.ts
state('jobPost', {
url: '/jobPost',
templateUrl: "/templates/jobPost.html",
controller: MyApp.Controllers.jobPostController,
controllerAs: 'jobPost'
})
.state('editjobPost', {
url: '/editjobPost',
templateUrl: "/templates/jobPost.html",
controller: MyApp.Controllers.jobPostController,
controllerAs: 'jobPost'
})
route.ts:
router.get('/jobPostData', function (req, res) {
console.log('getting jobPost data');
JobPost.find({}, function(err, jobposts) {
res.json(jobposts);
});
});
router.put('/jobPost', function (req, res, next) {
console.log('editing jobPost');
let jobPost = new JobPost({
jobTitle: req.body.jobTitle,
jobLocation: req.body.jobLocation,
jobDescription: req.body.jobDescription,
created_at: req.body.created_at
});
console.log(jobPost);
jobPost.save(function(err, jobPost) {
if (err) return next(err);
console.log('edited post');
res.send(jobPost);
});
});
jobPost.html:
<link rel="stylesheet" href="/css/jobPost.css" media="screen" title="no title" charset="utf-8">
<br><br><br><br><br><br><br>
<div class="container-fluid">
<div class="container">
<div class="row">
<div ng-show="jobPost.newForm" class="col-md-12" id="background">
<h1 class="headers">Post a Job</h1>
<form ng-submit="jobPost.newJobPost()" class="new_job_form" name="new_job_form">
<input ng-model="jobPost.jobPost.title" id="jobTitle" type="text" name="jobTitle" placeholder="job title"> <br><br>
<input ng-model="jobPost.jobPost.location" id="jobLocation" type="text" name="jobLocation" placeholder="job location"> <br><br>
<textarea ng-model="jobPost.jobPost.description" rows="8" cols="50"class="input-block-level" id="jobDescription" name="jobDescription" placeholder="Enter Description" ></textarea><br>
<input class="submit-btn" type="submit" name="submit" value="Submit">
</form>
<!-- <h2>{{jobPost.message}}</h2> -->
</div>
<div ng-show="jobPost.editForm" class="col-md-12" id="background">
<h1 class="headers">Edit a Job</h1>
<form ng-submit="jobPost.editJobPost()" class="edit_job_form" name="edit_job_form">
<input ng-model="jobPost.jobPost.title" type="text" name="jobTitle" value="{{editJobPost.editTitle}}"> <br><br>
<input ng-model="jobPost.jobPost.location" type="text" name="jobLocation" value="{{editJobPost.editLocation}}"> <br><br>
<textarea ng-model="jobPost.jobPost.description" rows="8" cols="50"class="input-block-level" name="jobDescription" value="{{editJobPost.editDescription}}" ></textarea><br>
<input class="submit-btn" type="submit" name="submit" value="Submit">
</form>
</div>
</div
</div>
</div>
</div>
<br><br>
<div class="container-fluid">
<div class="container">
<h1 class="headers">Your Jobs</h1>
<div class="row" ng-repeat="job in jobPost.jobPosts.slice(((jobPost.currentPage-1)*jobPost.itemsPerPage),((jobPost.currentPage)*jobPost.itemsPerPage)) | orderBy : 'created_at' ">
<h1></h1>
<div class="col-md-12 jobPosting panel-title">
<h2>{{job.jobTitle}}<a class="pull-right" ui-sref="editjobPost"><span ng-click="jobPost.editJobPost()" class="glyphicon glyphicon-cog"></a></h2>
<h3>{{job.jobLocation}}</h3>
<h3>{{job.jobDescription}}</h3>
</div>
</div>
<!-- <pagination total-items="jobPost.totalItems" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()" class="pagination-sm" items-per-page="jobPost.itemsPerPage"></pagination> -->
<ul uib-pagination total-items="jobPost.totalItems" items-per-page="jobPost.itemsPerPage" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()"></ul>
<!-- <ul uib-pagination total-items="totalItems" ng-model="JobPost" ng-change="pageChanged()"></ul> -->
<!-- <h4>Default</h4>
<h5>totalItems: {{jobPost.totalItems}}</h5>
<ul uib-pagination total-items="jobPost.totalItems" ng-model="jobPost.currentPage" ng-change="jobPost.pageChanged()"></ul> -->
<!-- <ul uib-pagination boundary-links="true" total-items="jobPost.totalItems" ng-model="jobPost.currentPage" class="pagination-sm" previous-text="‹" next-text="›" first-text="«" last-text="»"></ul>
<ul uib-pagination direction-links="false" boundary-links="true" total-items="jobPost.totalItems" ng-model="jobPost.currentPage"></ul>
<ul uib-pagination direction-links="false" total-items="jobPost.totalItems" ng-model="jobPost.currentPage" num-pages="smallnumPages"></ul>
<pre>The selected page no: {{jobPost.currentPage}}</pre>
<button type="button" class="btn btn-info" ng-click="jobPost.setPage(3)">Set current page to: 3</button> -->
<hr />
</div>
</div>
<script src="/js/jobForm.js" charset="utf-8"></script>
jobForm.ts:
$(document).ready(function() {
$('.new_job_form').on('submit', function(e){
e.preventDefault();
var jobTitle = $('#jobTitle').val();
var jobLocation = $('#jobLocation').val();
var jobDescription = $('#jobDescription').val();
$('#jobTitle').val('');
$('#jobLocation').val('');
$('#jobDescription').val('');
var data = {
jobTitle: jobTitle,
jobLocation: jobLocation,
jobDescription: jobDescription,
};
console.log(data);
$.ajax({
url: '/jobPost',
dataType: "json",
method: "POST",
data: data,
success: function(data, textStatus, jqXHR){
console.log("Successfully saved to database",data);
// var resultString = "<h4>"+data.jobTitle+"</h4><h4>"+data.jobLocation+"</h4><h4>"+data.jobDescription+"</h4>";
// $('.postResult').html(resultString);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
alert("Status: " + textStatus); alert("Error: " + errorThrown);
}
});
});
angular.module('MyApp').controller('jobPostController', function ($scope, $log) {
$scope.totalItems = 64;
$scope.currentPage = 1;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
$log.log('Page changed to: ' + $scope.currentPage);
};
$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
});
});
****EDIT to reflect answering stack overflow checklist
I have tried messing with the ui-sref and ng-click for the editJobPost section in the JobPost.html thinking maybe it was a routing error.
I then changed the editJobPost method in controller.js from the JobPost variable to JobPosts variable. Now that it runs and compiles (it didn't before) it throws this in the console:
HITTING EDIT
controllers.js:241 undefined
controllers.js:242 undefined
controllers.js:245 undefined
controllers.js:249 Title: undefined
controllers.js:250 Location: undefined
controllers.js:251 Description: undefined
angular.js:11881 PUT http://127.0.0.1:3000/jobPost/%7B%7Bjob._id%7D%7D 404 (Not Found)
I know that it means my declared variables are undefined, I just don't know where to start. what is wrong and why.

Related

AngularJS insert data to to JSON file

I have been trying and failing at this all day. I'm quite new to all this. This is a very simple angularJS learning exercise that I can't figure out.
My GET command successfully pulls the JSON data but the POST command in the addItem function is non-responsive. I believe I'm missing the server configuration but I don't know where I would put this.
There are only two files; the app and the json file (list.php); the content of both below. This app is currently running at:
http://pagemakr.com/list/L8/
THE APP - index.php:
<script>
var app = angular.module("myShoppingList", []);
app.controller("myCtrlx", function($scope,$http) {
$http.get("list.php").then(function (response) {
$scope.items = response.data.items;
});
$scope.addItem = function () {
var data = { "item":$scope.itemInput }
$http.post("list.php", data).then(function (response) {
if (response.data)
$scope.msg = "Success!";
}, function (response) {
$scope.msg = "Didn't Work!";
});
}
});
</script>
<div ng-app="myShoppingList" ng-cloak ng-controller="myCtrlx" class="w3-card-2 w3-margin" style="max-width:400px;">
<header class="w3-container w3-light-grey w3-padding-16"><h3>List</h3></header>
<ul class="w3-ul">
<li ng-repeat="x in items" class="w3-padding-16">{{x.item}}<span ng-click="removeItem($index)" style="cursor:pointer;" class="w3-right w3-margin-right">x</span></li>
</ul>
<div class="w3-container w3-light-grey w3-padding-16">
<div class="w3-row w3-margin-top">
<div class="w3-col s10">
<input placeholder="Add items here" ng-model="itemInput" class="w3-input w3-border w3-padding">
</div>
<div class="w3-col s2">
<button type="button" value="Submit" ng-click="addItem()" class="w3-btn w3-padding w3-green">Add</button>
</div>
</div>
<p class="w3-text-red">{{errortext}}</p>
</div>
</div>
THE JSON DATABASE - list.php:
{
"items":
[
{"item":"peas"},
{"item":"carrots"},
{"item":"jam"}
]
}

Angular Two-Way data-binding not refreshing ng-repeat on $scope change

My functionality is very simple, and I have to imagine very common. I have a page that lists a collection of 'age groups', and provides functionality to add an 'age group'. I simply would like to have the page immediately reflect the change when a new 'age group' is added.
In early versions, I had simply used the $rootScope in my service to put all 'age groups' in the $rootScope when the $http request was completed. On this latest refactoring I am removing all use of $rootScope in my app, and it is becoming problematic.
The code for the HTML view is as follows: [NOTE: all code considered extraneous has been removed from all code snippets]
<div id="tabContent" class="tab-pane fade in active" ng-show="subIsSelected(1)">
<div class="row">
<div class="col-xs-12">
<form class="form-inline">
<button type="button" class="btn btn-success" ng-click="openAddAgeGroup()">Add Age Group</button>
</form>
</div>
</div>
<hr />
<div class="row row-content">
<div class="col-xs-12">
<h4 ng-show="!areAgeGroups()">No current age groups.</h4>
<ul class="media-list" ng-show="areAgeGroups()">
<li class="media" ng-repeat="ageGroup in ageGroups" style="padding:10px; background: lightGray;">
<div class="media-left media-top" >
<img class="media-object img-thumbnail" style="width: 75px;" ng-src="./images/trfc.png" alt="club logo">
</div>
<div class="media-body">
<h3 class="media-heading" style="padding-top: 20px;">{{ageGroup.name}}</h3>
<button type="button" class="btn btn-xs btn-primary" style="width: 50px;" ng-click="openEditAgeGroup(ageGroup)">Edit</button>
<button type="button" class="btn btn-xs btn-danger" style="width: 50px;" ng-click="deleteAgeGroup(ageGroup)">Delete</button>
</div>
</li>
</ul>
</div>
</div>
</div>
when first loaded, the page correctly shows all 'age groups' that are in the $scope.ageGroups array.
On clicking the button to add an 'age group', an ng-dialog is created as follows:
$scope.openAddAgeGroup = function() {
console.log("\n\nOpening dialog to add age group");
ngDialog.open({ template: 'views/addAgeGroup.html', scope: $scope, className: 'ngdialog-theme-default', controller:"HomeController" });
};
and that dialog is populated as such:
<div class="ngdialog-message">
<div class="">
<h3>Add a New Age Group</h3>
</div>
<div> </div>
<div>
<form ng-submit="addAgeGroup()">
<div class="form-group">
<label class="sr-only" for="name">Age Group Display Name</label>
<input type="text" class="form-control" id="name" placeholder="age group name" ng-model="ageGroupForm.name">
</div>
<div class="form-group">
<label class="sr-only" for="birthyear">Birth Year</label>
<input type="text" class="form-control" id="birthyear" placeholder="birth year" ng-model="ageGroupForm.birthyear">
</div>
<div class="form-group">
<label class="sr-only" for="socceryear">Soccer Year</label>
<div class="input-group">
<div class="input-group-addon">U</div>
<input type="text" class="form-control" id="socceryear" placeholder="soccer year" ng-model="ageGroupForm.socceryear">
</div>
</div>
<button type="submit" class="btn btn-info">Add</button>
<button type="button" class="btn btn-default" ng-click=closeThisDialog("Cancel")>Cancel</button>
</form>
</div>
</div>
When the form is submitted, the 'age group' is added to the database, from the controller:
'use strict';
angular.module('ma-app')
.controller('HomeController', ['$scope', 'ngDialog', '$state', 'authService', 'coreDataService', 'userService', '$rootScope', 'clubService', 'schedulingService', function($scope, ngDialog, $state, authService, coreDataService, userService, $rootScope, clubService, schedulingService) {
...
$scope.addAgeGroup = function() {
coreDataService.addAgeGroup($scope.ageGroupForm)
.then(function(response) {
coreDataService.refreshAgeGroups()
.then(function(response) {
coreDataService.setAgeGroups(response.data);
$scope.ageGroups = coreDataService.getAgeGroups();
console.log("\n\n\nretrieved age groups and put them in scope");
console.log($scope.ageGroups);
ngDialog.close();
});
}, function(errResponse) {
console.log("Failed on attempt to add age group:");
console.log(errResponse);
});
};
The coreDataService is defined as follows:
'use strict';
angular.module('ma-app')
.service('coreDataService', ['$http', 'baseURL', 'googleGeolocateBaseURL', 'googleGeocodeKey', 'googleMapsBaseURL', function($http, baseURL, googleGeolocateBaseURL, googleGeocodeKey, googleMapsBaseURL) {
var ageGroups = {};
var ageGroupsLoaded = false;
this.getAgeGroups = function() {
return ageGroups;
};
this.setAgeGroups = function(newAgeGroups) {
ageGroups = newAgeGroups;
ageGroupsLoaded = true;
};
this.addAgeGroup = function(formData) {
//post age group:
var postString = '{ "birth_year": "' + formData.birthyear + '", "soccer_year": "U' + formData.socceryear + '", "name": "' + formData.name + '" }';
console.log("Posting age group with string: " + postString);
return $http({
url: baseURL + 'age_groups/',
method: 'POST',
headers: {
'content-type': 'application/json'
},
data: postString
});
};
}]);
So, when an 'age group' is added, console logging indicates that the new 'age group' is in the collection now stored in the $scope.ageGroups array, but the HTML's ng-repeat does not reflect the new 'age group'. Only when I navigate to another tab in the interface, and then return to the tab containing the 'age groups' is the newly added 'age group' displayed.
Updated:
After you update your value you need to tell angular that its been updated. If you wrap your code in a $timeout. On the next digest cycle the view will get updated. See here for more information.
...
$timeout(function() {
$scope.ageGroups = coreDataService.getAgeGroups();
// anything you want can go here and will safely be run on the next digest.
})
...
The $timeout basically runs on the next $digest cycle thus updating your value in the view.
I would suggest wrapping your ng-repeat part in a directive, fire an event on add method and listen to it from the directive:
this.addAgeGroup = function(formData) {
// do stuff
$scope.$broadcast('itemadded');
}
Inside your directive link function:
$scope.$on('itemadded', function() {
$scope.ageGroups = coreDataService.getAgeGroups();
});
I would recommend using the ControllerAs syntax which will refresh the ng-repeat, if the array to which it is bound to gets updated.
Refer the answer given here - ng-repeat not updating on update of array

Implementing a Session Factory

I have the following application implementing a Session Service that interacts with the HTML5 window.sessionStorage object. It works well. I'm trying to do the same as the service using a Session Factory but it doesn't work.
My application has the following files:
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>Services and Factories</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body ng-controller="sessionController as vm">
<div class="container">
<h1>Services and Factories</h1>
<div class="form-group row">
<div class="col-sm-4">
<label>Name</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.name">
</div>
</div>
<div class="form-group row">
<div class="col-sm-4">
<label>Nickname</label>
</div>
<div class="col-sm-8">
<input type="text" class="form-control" ng-model="vm.model.nickname">
</div>
</div>
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input ng-click="vm.setServiceSession()" type="button" class="btn btn-primary" value="Save with Service" />
<input ng-click="vm.getServiceSession()" type="button" class="btn btn-default" value="Retrieve from Service" />
<input ng-click="vm.clearServiceSession()" type="button" class="btn btn-default" value="Clear from Service" />
</div>
</div>
<pre>{{vm.model | json}}</pre>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<script src="app/app.js"></script>
<script src="app/sessionController.js"></script>
<script src="app/sessionService.js"></script>
</body>
</html>
app/app.js
angular.module('app', []);
app/sessionController.js
angular.module('app').controller('sessionController', ['sessionService', sessionController]);
function sessionController(sessionService) {
var vm = this;
vm.getServiceSession = function() {
vm.model = {
name: sessionService.get('name'),
nickname: sessionService.get('nickname'),
status: 'Retrieved by service on ' + new Date()
};
};
vm.setServiceSession = function() {
sessionService.save('name', vm.model.name);
sessionService.save('nickname', vm.model.nickname);
vm.getServiceSession();
};
vm.clearServiceSession = function() {
sessionService.clear();
vm.getServiceSession();
};
}
app/sessionService.js
angular.module('app').service('sessionService', ['$window', sessionService]);
function sessionService($window) {
this.save = save;
this.get = get;
this.clear = clear;
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
The Session Service works well. Then I try to add a Session Factory to do the same as the Session Service, but everything stops working. I add the following file:
app/sessionFactory.js
angular.module('app').factory('sessionFactory', ['$window', sessionFactory]);
function sessionFactory($window) {
return {
save: save,
get: get,
clear: clear
};
function save(key, value) {
$window.sessionStorage.setItem(key, value);
}
function get(key, value) {
return $window.sessionStorage.getItem(key);
}
function clear() {
$window.sessionStorage.clear();
}
}
And I modify:
index.html (adding 3 new buttons to for the Factory and the sessionFactory script)
<div class="form-group row">
<div class="col-sm-8 col-sm-offset-4">
<input type="button" class="btn btn-primary" value="Save with Factory" ng-click="vm.setFactorySession()" />
<input type="button" class="btn btn-default" value="Retrieve from Factory" ng-click="vm.getFactorySession()" />
<input type="button" class="btn btn-default" value="Clear from Factory" ng-click="vm.clearFactorySession()" />
</div>
</div>
...
<script src="app/sessionFactory.js"></script>
sessionController.js (adding the sessionFactory)
angular.module('app').controller('sessionController', ['sessionService', 'sessionFactory', sessionController]);
function sessionController(sessionService, sessionFactory) {
...
var mySessionFactory = new sessionFactory();
vm.getFactorySession = getFactorySession;
vm.setFactorySession = setFactorySession;
vm.clearFactorySession = clearFactorySession;
function getFactorySession() {
vm.model = {
name: mySessionFactory.get('name'),
nickname: mySessionFactory.get('nickname'),
status: 'Retrieved by Factory on ' + new Date()
};
}
function setFactorySession() {
mySessionFactory.save('name', vm.model.name);
mySessionFactory.save('nickname', vm.model.nickname);
getFactorySession();
}
function clearFactorySession() {
mySessionFactory.clear();
getFactorySession();
}
}
As factories and services are singletone you don't need to use new. Just remove that and do the same.
remove:
var mySessionFactory = new sessionFactory();
All the best.
You don't need to use new sessionFactory() when using a factory.
Instead, use sessionFactory.get('name') and it will work.
This is the main difference between service and factory.
Check this blog post for more insights.

Angularjs array push UI does not get's refreshed

I want to show a list of movies and add a new movie by adding it to the array.
The html file:
<!-- FOREACH the movies -->
<div ng-controller="homeController" ng-repeat="movie in movies | orderBy : order">
<div class="movie-wrapper">
<h1>{{movie.name}}</h1>
<p>IMDB: IMDB</p>
</div>
</div>
<!-- ADD a new movie to the array -->
<div ng-controller="homeController">
<h3>Add new movie:</h3>
<form name="movieForm" ng-submit="addMovie(movieInfo)">
<div class="form-group new-movie">
<label for="Title">Title:</label>
<input type="text" class="form-control" name="title" ng-model="movieInfo.title">
</div>
<div class="form-group new-movie">
<label for="IMDB">IMDB:</label>
<input type="text" class="form-control" name="imdb" ng-model="movieInfo.imdb">
</div>
<button type="submit" class="btn btn-primary">Add movie</button>
</form>
</div>
The javascript file:
var app = angular.module('movie-app', ["ngRoute"]);
app.controller("homeController", function($scope) {
$scope.movies = getMovies();
// Method to add a new movie
$scope.addMovie = function(movieInfo) {
$scope.movies.push({
name : movieInfo.title,
imdb_url: movieInfo.imdb
});
console.log("Movie added");
}
});
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
After pressing the submit button, in the console I did not get any error message, but somehow the UI does not get's refreshed.
I think that somehow the controller does not get a reference/bind to the same array or dom element when I'm pushing the new entry.
First of all, i'm pretty sure you should have an error in your console
You make 3 mistakes :
1. You have an error in your getMovies() function (missing curly brackets {})
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
Why curly brackets are important ?
name and imdb_url are properties object. In JavaScript, an object must have curly brackets before and after. But your function getMovies returns and array of 1 element, so you have to surround your object with brackets []
2. You also have an error when you call console.log (missing quote ")
console.log("Movie added);
3. And the last one : you have to remove the parenthesis }) (the line after console.log)
The result :
angular.module('movieApp', [])
.controller("homeController", function($scope) {
$scope.movies = getMovies();
// Method to add a new movie
$scope.addMovie = function(movieInfo) {
$scope.movies.push({
name: movieInfo.title,
imdb_url: movieInfo.imdb
});
console.log("Movie added");
};
});
function getMovies() {
return [{
name: 'Inception',
imdb_url: 'http://www.imdb.com/title/tt1375666/'
}];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="movieApp" ng-controller="homeController">
<!-- FOREACH the movies -->
<div ng-repeat="movie in movies | orderBy : order">
<div class="movie-wrapper">
<h1>{{movie.name}}</h1>
<p>IMDB: IMDB
</p>
</div>
</div>
<!-- ADD a new movie to the array -->
<div>
<h3>Add new movie:</h3>
<form name="movieForm" ng-submit="addMovie(movieInfo)">
<div class="form-group new-movie">
<label for="Title">Title:</label>
<input type="text" class="form-control" name="title" ng-model="movieInfo.title">
</div>
<div class="form-group new-movie">
<label for="IMDB">IMDB:</label>
<input type="text" class="form-control" name="imdb" ng-model="movieInfo.imdb">
</div>
<button type="submit" class="btn btn-primary">Add movie</button>
</form>
</div>
</div>

AngularJS - Convert Object to Array for UI Bootstrap Pagination

I know this might have been already answered, but I have been unsuccessful in applying any solutions I found to my example. I am trying to enabled pagination on my products list page using UI Bootstrap and allow the user to filter said results with a search.
I have an object that is defined as such:
$scope.products = [{"_id": ObjectID("0000000"), "name":"Product", "description": "Product Description"}];
So far I have been able to pull my products from a restangular service, but I am getting the following console error: Error: [filter:notarray] Expected array but received {} when I added the pagination/search functionality. I know I need to convert my object to an array, but I have not been able to successfully convert it. The two examples I tried are posted below. Any help will be greatly appreciated.
My Products list view
<div ng-controller="paginationCtrl" class="row">
<div class="col-lg-12">
<div class="pull-left">
<form>
<div class="input-group product-searchs" ng-controller="SearchCtrl">
<label class="sr-only" for="searchProducts">Search</label>
<span class="input-group-addon search-icon"><i class="fa fa-search" aria-hidden="true"></i></span>
<input type="text" class="form-control" id="searchProducts" ng-model="search.name" placeholder="Search for products">
<span class="input-group-addon clear-icon">
<button type="button" ng-click="clearSearch()">
<i class="glyphicon glyphicon-remove" aria-hidden="true"></i>
</button>
</span>
</div>
</form>
</div>
</div>
<div class="col-lg-12">
<div class="list-group">
<a ui-sref="productDetails({id:product._id})" class="list-group-item clearfix" ng-repeat="product in filteredProducts = (products | filter: search | startFrom: (currentPage - 1) * itemsPerPage | limitTo: itemsPerPage | orderBy:orderProp)">
<div class="page-header clearfix">
<h2 class="pull-left"><i class="fa fa-diamond"></i> {{product.name}}</h2>
<span class="pull-right product-price {{product.price | currency}}</span>
</div>
{{product.description}}
</a>
</div>
</div>
<div class="col-lg-12">
<pagination class="pull-right" page="currentPage" total-items="totalItems" ng-model="currentPage" max-size="maxSize" ng-change="pageChanged() items-per-page="itemsPerPage" num-pages="numPages"></pagination>
</div>
</div>
I know I might have some extra dependencies injections, which I will remove once I get it working correctly.
My controller
angular.module('gemStoreApp')
.controller('paginationCtrl', ['$scope', '$log', 'filterFilter', 'productsService', 'Restangular', '$filter', function ($scope, $log, filterFilter', productsService, Restangular, $filter) {
$scope.search = {}
$scope.filteredProducts = [];
//Option 1
angular.forEach($scope.products, function(product) {
$scope.filteredProducts.push(product);
});
//Option 2
//for (var key in $scope.products) {
//var tempProducts = {};
//tempProducts[key] = $scope.products[key];
//$scope.filteredProducts.push(tempProducts);
//});
$scope.currentPage = 1;
$scope.maxSize = 100;
$scope.itemsPerPage = 10;
$scope.$watch('search', function(newVal, oldVal) {
$scope.filteredProducts = filterFilter($scope.products, newVal);
$scope.totalItems = $scope.filteredProducts.length;
}, true);
//I also tried this
//$scope.$watch('search, function(newSearch) {
//$scope.filteredProducts = $filter('filter')($scope.products, $scope.search);
// $scope.totalItems = $scope.filteredProducts.length;
//});
}])
My service
angular.module('gemStoreApp.productService',['ngResource'])
.factory('productsService', function(Restangular) {
return Restangular.service('products');
});
My Products Controller
angular.module('gemStoreApp')
.controller('ProductsCtrl', ['$scope', 'productsService', function ($scope, productsService) {
$scope.products = {};
productsService.getList().then(function(products){
$scope.products = products;
});
}]);
Added the Restangular setRestangularFields and setRequestInterceptor methods to my app.js file, which gets the search/filtering function working, but I am still getting an Expected array but received {} error
RestangularProvider.setRestangularFields({
id: '_id.$oid'
});
RestangularProvider.setRequestInterceptor(function(elem, operation) {
if (operation === 'put') {
elem._id = undefined;
return elem;
}
return elem;
});
I have created a Plunker version that appears to be working correctly..
Plunker example.
Created an updated Plunker with the issue I am seeing my local. The issue is that the Pagination is not working correctly. It is displaying only 10 items as I want it to, but clicking on the two does not switch to page 2. Plunker example
I saw several things wrong in your example. I believe you don't need the ng-controller="SearchCtrl" in your html.
Also, the main point of having the filter in your ng repeat is to not use the watch event of the search text input. So you should use the products array and apply the filter against it. If you want to use filteredProducts, I left a function in my example below. I initialized the variables since I don't have access to your restless apis.
var app = angular.module('myApp', []);
app.filter('startFrom', function() {
return function(input, start) {
if(input) {
start = +start; //parse to int
return input.slice(start);
}
return [];
}
});
app.controller('paginationCtrl', ['$scope', '$log', '$filter', function ($scope, $log, $filter) {
$scope.search = {name: "Product"}
$scope.products = [{"_id": "0000000", "name":"Product", "description": "Product Description"},
{"_id": "0000000", "name":"Product 2", "description": "Product Description 2"}];
$scope.filteredProducts = [];
$scope.currentPage = 2;
$scope.maxSize = 100;
$scope.itemsPerPage = 10;
$scope.startFrom = ($scope.currentPage - 1) * $scope.itemsPerPage;
var filterProducts = function(newVal){
$scope.filteredProducts.splice(0, $scope.filteredProducts.length);
angular.forEach($scope.products, function(product) {
if(product.name == newVal){
$scope.filteredProducts.push(product);
}
});
}
$scope.$watch('search.name', function(newVal, oldVal) {
filterProducts(newVal);
$scope.totalItems = $scope.filteredProducts.length;
}, true);
$scope.$watch('currentPage', function(newVal, oldVal) {
$scope.startFrom = ($scope.currentPage - 1) * $scope.itemsPerPage;
}, true);
$scope.$watch('itemsPerPage', function(newVal, oldVal) {
$scope.startFrom = ($scope.currentPage - 1) * $scope.itemsPerPage;
}, true);
}])
<!DOCTYPE html>
<html>
<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="paginationCtrl as ctrl" class="row">
<div class="col-lg-12">
<div class="pull-left">
<div class="input-group product-searchs" >
<label class="sr-only" for="searchProducts">Search</label>
<span class="input-group-addon search-icon"><i class="fa fa-search" aria-hidden="true"></i></span>
<input type="text" class="form-control" ng-model="search.name" placeholder="Search for products" />
<span class="input-group-addon clear-icon">
<button type="button" ng-click="clearSearch()">
<i class="glyphicon glyphicon-remove" aria-hidden="true">test</i>
</button>
</span>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="list-group">
<a ui-sref="productDetails({id:product._id})" class="list-group-item clearfix" ng-repeat="product in products | filter: search.name | limitTo: itemsPerPage | startFrom: 0 ">
{{product.name}}
{{product.description}}
<br/>
</a>
</div>
</div>
<div class="col-lg-12">
<pagination class="pull-right" page="currentPage" total-items="totalItems" ng-model="currentPage" max-size="maxSize" ng-change="pageChanged()" items-per-page="itemsPerPage" num-pages="numPages"></pagination>
</div>
</div>
</div>
</body>
</html>
Edit
After watching your plunker, you do not need to add the filteredProducts to your controller since you are doing the filtering in your view. By adding the filteredProducts to your view, it will also be accessible in your controller with $scope.filteredProducts.
So replace the bottom of your html with the code below and also delete all that code that handles the filteredProducts from your controller:
<div class="col-lg-12">
<div class="list-group">
<a ui-sref="productDetails({id:product._id})" class="list-group-item clearfix" ng-repeat="product in filteredProducts = (products | filter: search.name | limitTo: itemsPerPage | startFrom: 0) ">
{{product.name}}<br/>
{{product.description}}
</a>
</div>
</div>
<div class="col-lg-12">
<pagination class="pull-right" page="currentPage" total-items="filteredProducts.length" ng-model="currentPage" max-size="maxSize" ng-change="pageChanged()" items-per-page="itemsPerPage" num-pages="numPages"></pagination>
</div>
If you want to do everything manually (which I do not recommend), you have to change your html to be product in filteredProducts, when it starts add all your products to the filteredProducts list and keep your code in the controller. Also you will have to fill the filteredProducts list again when the search is empty.

Resources