I have an AngularJS app with a list of users with an 'Edit' button beside each user. Each user has a number of subjects associated with them. When I click on 'Edit', it opens a form in which you can edit user details, and select associated subjects from a list of checkboxes. I'm trying to figure out how to bind the subject checkboxes so that the subjects which the
user is already associated with are checked, and the rest are unchecked. Any suggestions appreciated.
My HTML:
<form name="UserEditForm">
Name: <br /> <input type="text" name="name" ng-model="user.name"> <br />
{{name}}
Email: <br /> <input type="text" name="name" ng-model="user.email"> <br />
{{email}}
<div class="control-group">
<label class="control-label" for="inputSubjects">Subjects:</label>
<div class="form-group">
<label ng-repeat="subject in subjects" class="checkbox">
<input type="checkbox" ng-checked="{user.subjects}" name="selectedSubjects[]" value="{{subject.id}}" ng-model="subject.selected"> {{subject.name}}
</label>
</div>
<br />
<a ng-click="updateUser()" class="btn btn-small btn-primary">Save Changes</a>
</form>
My UserEditCtrl:
angular.module('myApp.controllers')
.controller('UserEditCtrl', ['$scope', '$routeParams','SubjectsFactory', 'UserFactory', '$location',
function ($scope, $routeParams, SubjectsFactory, UserFactory, $location) {
// callback for ng-click 'updateUser':
$scope.updateUser = function () {
$scope.user.subjects = $scope.selection;
UserFactory.update($scope.user);
$location.path('/users');
};
// callback for ng-click 'cancel':
$scope.cancel = function () {
$location.path('/users');
};
$scope.user = UserFactory.show({id: $routeParams.userid});
$scope.subjects = SubjectsFactory.query();
$scope.selection = [];
// helper method
$scope.selectedSubjects = function selectedSubjects() {
return filterFilter($scope.subjects, { selected: true });
};
// watch subjects for changes
$scope.$watch('subjects|filter:{selected:true}', function (nv) {
$scope.selection = nv.map(function (subject) {
return subject.id;
});
}, true);
}]);
As #jkinkead said, your code looks good, I fixed the ng-checked binding in accordance with your ng-model expression
Here's a simplified plunker : http://plnkr.co/edit/qaIBExtVbNdSXlQlbMym?p=preview
EDIT 1: I edited and improved the plunker to get closer to your case.
Related
So, I am creating a web app, where one page I have a user list and on the second page, I have the users details page. On the second page, I have a confirm button where I want to remove that user when the "Confirm" button is clicked with a 200 Status code. However, I am getting a DELETE : 405 (Method Not Allowed). So, here is my code down below. Please tell me or help me fix this problem. Thank you in advance.
Here is my code.
<div ng-controller="MyCtrl">
<div ng-repeat="person in userInfo.lawyers | filter : {id: lawyerId}">
<a class="back" href="#/lawyer">Back</a>
<button type="button" class="edit" ng-show="inactive" ng-click="inactive = !inactive">
Edit
</button>
<button type="submit" class="submit" ng-show="!inactive" ng-click="inactive = !inactive">Save</button>
<button class="btn btn-primary" ng-click="doDelete(id)">Confirm</button>
<div class="people-view">
<h2 class="name">{{person.firstName}}</h2>
<h2 class="name">{{person.lastName}}</h2>
<span class="title">{{person.email}}</span>
<span class="date">{{person.website}} </span>
</div>
<div class="list-view">
<form>
<fieldset ng-disabled="inactive">
<legend>Basic Info</legend>
<b>First Name:</b>
<input type="text" ng-model="person.firstName">
<br>
<b>Last Name:</b>
<input type="text" ng-model="person.lastName">
<br>
<b>Email:</b>
<input type="email" ng-model="person.email">
</fieldset>
</form>
</div>
</div>
</div>
Services
app.factory('people', function ($http) {
var service = {};
service.getUserInfo = function () {
return $http.get('https://api-dev.mysite.io/admin/v1/unconfirmed_lawyers');
};
service.confirmUser = function (lawyerId) {
return $http.put('https://api-dev.mysite.io/admin/v1/lawyers/{lawyerId}/confirm');
};
return service;
});
LawyerController
app.controller('LawyerController', ['$scope', 'people', '$routeParams',
function ($scope, people, $routeParams) {
$scope.lawyerId = $routeParams.id;
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
});
}]);
HomeController
var isConfirmed = false;
app.controller('HomeController', function($scope, people, $http) {
if (!isConfirmed) {
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
}, function (error) {
console.log(error)
});
}
});
App.js
$scope.doDelete = function(lawyer) {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
$scope.userInfo.lawyers.splice(index, 1);
location.href = '#/lawyer';
};
If you changed your HTML, so you passed the person instead.
<button class="btn btn-primary" ng-click="doDelete(person)">Confirm</button>
You can use this to find the index within the lawyers, then remove it.
$scope.doDelete = function(lawyer) {
var index = $scope.userInfo.lawyers.indexOf(lawyer);
$scope.userInfo.lawyers.splice(index, 1)
};
The issue is your are using $http.delete which performs an HTTP Delete request. This doesn't sound like something you intended.
I just began to study angular, tried to make some kind of SPA, but faced with problem of editing data in it. The obect is visible in console, but it hasn't appear on page, what I did wrong?
Here my controller:
var app = angular.module("testModule", ['ngRoute']);
app.config(function ($routeProvider){
$routeProvider.when('/', {
templateUrl: 'pages/main.html',
controller: 'addCtrl'
})
.when('/save', {
templateUrl: 'pages/save.html',
controller: 'editCtrl'
})
.when('/edit', {
templateUrl: 'pages/edit.html',
controller: 'addCtrl'
})
})
app.service('dataService', function($http) {
var data = {};
data.list = [];
var getData = function() {
$http.get("model/data.json").then(function (response) {
data.list = response.data;
});
}
return {
getDataFromJson: getData,
getData: data,
}
});
app.controller("mainCtrl", function($scope, dataService) {
dataService.getDataFromJson();
});
app.controller("editCtrl", function($scope, dataService) {
$scope.data = dataService.getData;
$scope.editData = function(adverse){
$scope.adverse= adverse;
console.log($scope.adverse)
}
});
and the part of page:
<div class="panel">
<form name="addForm" >
<div class="well" >
<div class="form-group">
<label for="name">Name:</label>
<input type='text' id="name" class="form-control" ng-model="adverse.name" placeholder={{adverse.name}} />
<label for="shop">Shop:</label>
<input type='text' id="shop" class="form-control" ng-model="adverse.shop" placeholder="{{adverse.shop}}" />
<label for="begin">Begin:</label>
<input id="begin" class="form-control" ng-model="adverse.begin" placeholder="{{adverse.begin}}" >
<label for="end">End:</label>
<input id="end" class="form-control" ng-model="adverse.end" placeholder="{{adverse.end}}" />
<button type="submit" class="btn btn-primary btn-block add_btn" ng-click="editData(adverse)">
Edit
</button>
</div>
</div>
</form>
</div>
Also here is a screenshot: the props of object suppose to be in the inputs but it hasn't.
enter image description here
If possible can you give me an example how I can do it by another way?
Recreated your scenario in this plunker. But it works. Please have a look at this plunker where you alo can see the StateProvider which is used instead of NgRoute
One thing I see which is incorrect is that you are sending the adverse object in the function and then setting the param to the scope adverse.
The thing is that the $scope.adverse already holds the values so you don't need to pass the value and setting it to the scope again. Remeber the scope is your glue between the view and ctrl
$scope.editData = function(){
console.log($scope.adverse)
}
Screencast: http://screencast-o-matic.com/watch/cDjX00isoo
All Javascript: http://fontget.com/js/all.js (at the bottom)
Demo of the issue: http://www.fontget.com
So I have this issue that I have been dealing with for a bit and can't seem to be able to figure it out. I am trying to give users the option of sorting the results from the database by clicking on a radio button with the specific filter.
When I click on the radio button I can see in the console that the correct url is grabbed using AJAX but the list is not getting updated in the view.
The page works when it is loaded for the first time (no sort filters).
The controller:
FontGet.controller('mainController', ['$scope', 'FontService', '$location', '$rootScope', '$routeParams', function($scope, FontService, $location, $rootScope, $routeParams) {
$rootScope.hideFatMenu = false;
$scope.navCollapsed = true;
$scope.isSettingsCollapsed = true;
$rootScope.header = "Welcome to FontGet.com!";
$scope.sortBy = 'new';
$scope.fonts = {
total: 0,
per_page: 10,
current_page: ((typeof($routeParams.page) !== 'undefined') ? $routeParams.page : 1),
loading: true
};
$scope.setPage = function() {
FontService.call('fonts', { page: $scope.fonts.current_page, sort: $scope.sortBy }).then( function(data) {
$scope.fonts = data.data;
$scope.fonts.loading = false;
document.body.scrollTop = document.documentElement.scrollTop = 0;
});
};
$scope.$watch("sortBy", function(value) {
$scope.setPage();
});
$scope.$watch("searchQuery", function(value) {
if (value) {
$location.path("/search/" + value);
}
});
$scope.categories = FontService.categories();
$scope.setPage();
}]);
The View:
<div class="fontdd" ng-repeat="font in fonts.data" >
<!-- Stuff goes here. This is populated correctly when page initially loads -->
</div>
The sort buttons:
<ul class="radiobtns">
<li>
<div class="radio-btn">
<input type="radio" value="value-1" id="rc1" name="rc1" ng-model="sorts" ng-change="sortBy = 'popular'">
<label for="rc1" >Popularity</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-2" id="rc2" name="rc1" ng-model="sorts" ng-change="sortBy = 'trending'">
<label for="rc2">Trending</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-4" id="rc4" name="rc1" checked="checked" ng-model="sorts" ng-change="sortBy = 'new'">
<label for="rc4">Newest</label>
</div>
</li>
<li>
<div class="radio-btn">
<input type="radio" value="value-3" id="rc3" name="rc1" ng-model="sorts" ng-change="sortBy = 'alphabetical'">
<label for="rc3">Alphabetical</label>
</div>
</li>
</ul>
You will notice that the ng-model for the radio buttons is not set to sortBy. The reason for this is that if I set it to sortBy the AJAX call is made 4 times (no clue why thi is happening).
You're using a $scope.$watch function to watch for changes in the sortBy scope variable. You should try removing the watch and change your sort buttons' ng-change event to this:
<div class="radio-btn">
<input type="radio" value="value-1" id="rc1" name="rc1" ng-model="sorts" ng-change="Sort('popular')">
<label for="rc1" >Popularity</label>
</div>
In your controller, create a Sort() function:
$scope.Sort = function(sortBy) {
$scope.sortBy = sortBy;
$scope.setPage();
}
You don't really need to use $watch when you can just call a function and pass in the appropriate information.
I have a form, when I submit it, it pushes some object to my array. Beneath that form I have a table that shows all items in that array. I want my table to update automatically (without refreshing the page) when new item pushed.
Submit button:
<button type="submit" class="btn btn-default" ng-click="updateTable()">Pay</button>
In my controller:
$scope.updateTable = function() {
setTimeout(function () {
$scope.$apply();
$scope.$digest();
}, 0);
};
However, it does not work.
I tried different approaches like $watch service, but i`ve got the same result.
Table
<div class="row paytable">
<div class="col-xs-10 col-xs-offset-1">
{{payments.length}}
<table class="table table-hover ">
<tr>
<td>Id</td>
<td>Amount</td>
<td>Cause</td>
</tr>
<tr ng-repeat="item in payments">
<td>{{item.id}}</td>
<td>{{item.amount}}</td>
<td>{{item.cause}}</td>
</tr>
</table>
</div>
</div>
Controller
app.controller('mainController', [ 'user', '$rootScope', '$scope', 'payment', '$timeout', function(user, $rootScope, $scope, payment, $timeout) {
user.getUsers();
user.newUser();
$rootScope.currentUser = user.currentUser();
$scope.payments = payment.getPayments();
$scope.newPayment = payment.newPayment;
$scope.updateTable = function() {
setTimeout(function () {
console.log('apply ------------');
$scope.$apply();
$scope.$digest();
}, 0);
};
$scope.showPayMessage = function() {
console.log('im here');
$scope.showSM = true;
$timeout(function() {
$scope.showSM = false;
}, 2000);
};
}]);
payment - my service for array manipulation.
Form
<div class="newpay row" >
<div class=" col-xs-10 col-xs-offset-1">
<h1>Hello, {{currentUser.name}}</h1>
<h4 ng-show="showSM" class="bg-success">Payment confirmed</h4>
<form name="inputform" ng-submit="newPayment(amount, cause); showPayMessage();">
<div class="form-group">
<label for="exampleInputEmail1">Amount</label>
<input type="number" name="amount" ng-model="amount" class="form-control" id="exampleInputEmail1" placeholder="Amount" required>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Cause</label>
<input type="text" name="cause" ng-model="cause" class="form-control" id="exampleInputPassword1" placeholder="Cause" required>
</div>
<button type="submit" class="btn btn-default" ng-click="updateTable()">Pay</button>
</form>
</div>
</div>
payments: {{payments.length}}
<payments-table payments="payments"></payments-table>
To display that table I created directive.
$scope.$apply and $scope.$digest are better suited for working with 3rd party libraries or testing. In your case Angular is well aware to your changes. The thing is, your payments array, that resides in a service should be queried again after submitting a new item (unless you have a direct reference to the array, then no query should be made).
Like this:
View
<form name="inputform" ng-submit="onSubmit()">
Controller
$scope.onSubmit = function() {
newPayment($scope.newItemAmount, $scope.newItemCause); // Assuming they are properties in the controller
showPayMessage();
$scope.payments = payment.getPayments(); // getting the updated array
}
I have a list of dynamically generated radio boxes in html:
**index.html**
<div id="choiceGraphId1" class="radio-button" ng-controller="selectGraph1">
<div ng-repeat="choice1 in choices1">
<table>
<label class="labelClass" > <td > {{choice1.graphChoice1}} </td> </label> <td>  </td> <label class="labelClass" > <td> <input type="radio" ng-model="$parent.selectedGraph1" ng-value="choice1.graphChoice1" name="graphChoice1" required /> </td> </label></table></div></div>
Angular Controller:
app.controller('selectGraph1', function ($scope,$rootScope) {
$rootScope.selectedGraph1="Choice1";
$rootScope.choices1 = [{
graphChoice1: "Choice1"
}, {
graphChoice1: "Choice2"
}
];
alert($rootScope.selectedGraph1);
});
I want to pass the value of $rootScope.selectedGraph1 to
PrintReportToPDF controller :
**index.html**
<div class="buttonsClass" ng-controller="**PrintReportToPDF**">
<button popover="Click button to open selected date range PDF Report in a new tab"
popover-trigger="mouseenter" type="button" class="btn btn-info"
ng-disabled="dataLoading"
ng-click="PrintReportToPDF()">
<i class="fa fa-file-pdf-o icon"></i>
Preview PDF Report
</button>
...
app.controller('PrintReportToPDF', function($scope, $rootScope, $window, UrlServices , StatsByDatePDF, StatsByDateExcel, Flash) {
//Preview PDF Report
alert($rootScope.selectedGraph1);
alert($rootScope.selectedGraph2);
$scope.PrintReportToPDF_1_StatisticsByDate = function() {
....
I am trying to access the $rootScope.selectedGraph1 in my controller
but its value is undefined in PrintReportToPDF controller.
What am I doing wrong here?
You can find your solution here
var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
return {
name : 'anonymous'
};
});
function MyCtrl($scope, UserService) {
$scope.name = UserService.name;
}