I have an ember application with two models, user and subject. Each user has a number of subjects associated with them. I have a user/create template in which you can input a new users details, ie their name, email address and associated subjects. The subjects are selected from a list of checkbox values, driven by the subjects in the subject controller. My problem is that when I click on save, the controller seems to skip over the subject selection and doesn't add them to the JSON payload. Can anyone help?
Create Template:
<script type = "text/x-handlebars" id = "user/create">
<div class="modal fade" id="createModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">New User</h4>
</div>
<div class="modal-body">
<div class = "input-group">
<form>
<h5>First Name</h5>
{{input value=firstName}}
<h5>Last Name</h5>
{{input value=lastName}}
<h5>Email</h5>
{{input value=email}}
<h5>Subjects</h5>
{{#each subject in subjects}}
<label>
{{view Ember.Checkbox Binding="id"}}
{{subject.name}}
</label><br />
{{/each}}
</form>
</div>
</div>
<div class="modal-footer">
<a {{action close target="view"}} href="#" class="btn btn-default">Cancel</a>
<a data-dismiss="modal" {{action "save"}} class="btn btn-primary">Save changes</a>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</script>
UserCreateView:
App.UserCreateView = Ember.View.extend({
didInsertElement:function(){
$('#createModal').modal('show');
var self = this;
$('#createModal').on('hidden.bs.modal', function (e) {
self.controller.transitionToRoute("users");
});
},
actions:{
close:function(){
this.$(".close").click();
},
save: function(){
alert('(in view) saved in view');
this.controller.send("save");
self.controller.transitionToRoute("users");
this.$(".close").click();
$('#createModal').modal('hide');
}
},
)};
CreateController:
App.UsersCreateController = Ember.ObjectController.extend({
subjects: function() {
return this.store.find('subject');
}.property(),
actions: {
save: function(){
alert('(UsersCreateController) SENDING A POST REQUEST');
var newUser = this.store.createRecord('user', this.get('model'));
console.log("newUser", newUser);
newUser.save();
this.transitionToRoute('users');
$('#createModal').modal('hide');
}
}
});
The first thing I would look at is the binding attribute you are using on your checkbox(es). For non-checkbox or {{input}} you bind via the value attribute. BUT - for checkboxes you must bind on the "checked" attribute.
Take a look at http://emberjs.com/guides/templates/input-helpers/ - about halfway down under Checkboxes for more info, it will show the accepted attributes, etc.
I experienced the same issue wherein this:
{{input type="checkbox" class="input-small" id="inputCache" value=cache}}
did not work with regard to passing in the checkbox-values to the action handling the submit (other values were passed in and persisted fine), whereas simply changing the attribute to this:
{{input type="checkbox" class="input-small" id="inputCache" checked=cache}}
solved the entire problem.
Hopefully this will do the trick. Good luck :-)
Related
I have seen similar questions related to this but this is different. In most of the questions, ng-hide/show fired on ng-click event.
Here is the code.
$scope.showDetails = 0;
$scope.delete = function(event) {
alert(event.target.id);
$scope.showDetails = 1;
//There would be more code for delete function. Some Ajax calls will be here.
}
<div ng-repeat="suggestions1 in suggestions">
<div class="col-xs-12 alert alert-info" ng-if="showDetails == '0'">
<center>
<a ng-click="delete($event)" id={{suggestions1.id}} class = "btn btn-danger">
<font size = "4">
<i class="fa fa-times-circle"></i>
</font>
Delete
</a>
</center>
</div>
</div>
Problem is when I click on the button it hides all the divs. I am expecting one div to hide but it is hiding all the div inside ng-repeat.
I have searched for multiple questions and tried the solutions but the issue still persists.
In that case you need to have a property named showDetails in each object of your new_suggestions array and enable ng-if based on that.
<div ng-repeat="suggestions1 in news_suggestions">
<div class="col-xs-12 alert alert-info" ng-if="suggestions1.showDetails == '0'">
Your code is logically wrong. You are keeping only one copy of showDetails variable. You need some property which is related to each object.
Try like this
$scope.delete = function(index) {
$scope.news_suggestions[index].hideDetails = true;
}
<div ng-repeat="suggestions1 in news_suggestions">
<div class="col-xs-12 alert alert-info" ng-hide="suggestions1.hideDetails">
<center> <a ng-click="delete($index)" id={{suggestions1.id}} class = "btn btn-danger"> <font size = "4"><i class="fa fa-times-circle"></i></font> Delete </a> </center></div></div>
There's one more approach:
// add an array
$scope.hiddenIds = [];
<div ng-repeat="suggestions1 in news_suggestions">
<!-- check if hidden -->
<div ng-hide=" hiddenIds.indexOf(suggestions1.id)>-1 " class="col-xs-12 alert alert-info">
<center>
<!-- remove/add to hidden array on click -->
<a ng-click=" hiddenIds.indexOf(suggestions1.id)>-1 ? hiddenIds.splice(hiddenIds.indexOf(suggestions1.id),1) : hiddenIds.push(suggestions1.id) " id={{suggestions1.id}} class = "btn btn-danger">
Here you don't modify the existing collection of elements.
Hint: if you hide the show/hide button, you won't be able to show the element back again. So you probably want to change your html layout a bit ;)
EDIT
Version 2:
You can always move it from your html to the scope.
// add an array
$scope.hiddenIds = [];
$scope.checkHide = function(suggestions1){
return $scope.hiddenIds.indexOf(suggestions1.id)>-1;
};
$scope.clickHide = function(suggestions1){
$scope.hiddenIds.indexOf(suggestions1.id)>-1 ? $scope.hiddenIds.splice($scope.hiddenIds.indexOf(suggestions1.id),1) : $scope.hiddenIds.push(suggestions1.id) ;
};
<div ng-repeat="suggestions1 in news_suggestions">
<!-- check if hidden -->
<div ng-hide="checkHide(suggestions1)" class="col-xs-12 alert alert-info">
<center>
<!-- remove/add to hidden array on click -->
<a ng-click="clickHide(suggestions1)" id={{suggestions1.id}} class = "btn btn-danger">
EDIT 2
If you don't need that element in news_suggestions (you're not planning to show it back again), you can simply remove it, which is even easier :)
$scope.remove = function(i){
$scope.news_suggestions.splice(i,1);
};
<div ng-repeat="suggestions1 in news_suggestions track by $index">
<div class="col-xs-12 alert alert-info">
<center>
<!-- remove by index on click -->
<a ng-click="remove($index)" id={{suggestions1.id}} class = "btn btn-danger">
JSBin
Yes, something wrong with your logic. Try this:
$scope.delete = function(el){
el.hideDetails = true;
}
<div ng-repeat="suggestions1 in news_suggestions">
<div class="col-xs-12 alert alert-info" ng-hide="hideDetails">
<center> <a ng-click="delete(this)" id={{suggestions1.id}} class = "btn btn-danger"> <font size = "4"><i class="fa fa-times-circle"></i></font> Delete </a> </center></div></div>
I am using angularjs and spring mvc for my application. At first I am displaying all the placements with one button Placed Candidates. I am doing ng-repeat for displaying all the placements.
Here is my html.
<div class="row" data-ng-repeat="placement in placements">
<div class="col-xs-12 col-sm-12 col-md-12">
<h5>{{placement.companyName}}</h5>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<h6>{{placement.placementDate | date:'dd MMM yyyy'}}</h6>
Company Target (appox):10 Achieved:
</div>
<a href="javascript:void(0);" data-ng-
click="placedcandidatespopup(placement.placementId);">//here i can
get particular placementId but how to pass this id to
savePlacementStudents() method in controller.js???//
PlacedCandidates
</a>
</div>
I am calling one modal popup function. Here is controller.js
$scope.placedcandidatespopup = function()
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$(".placedcandidates").modal("show");
}
I am calling modal by name "placedcandidates".
Here is the modal
<div class="modal right fade placedcandidates" id="myModal1"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel2">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6" data-ng-
repeat="student in allusers">
<input id="{{student.studentId}}" type="checkbox" value="
{{student.studentId}}" data-ng-
checked="selection.indexOf(student.studentId) >-1"
data-ng-click="toggleSelection(student.studentId)"/>
<label for="{{student.studentId}}"></label>
{{student.firstName}}
</div>
</div>
</div>
<div class="modal-footer" style="position: fixed;">
<input type="button" value="Submit" class="btn" data-ng-
click="savePlacementStudents()">
</div>
</div>
</div>
</div>
After clicking on button popup modal will display with all Students with checkboxes placed beside them.Now I am able to save studentId into database.But I am not able to pass placementId for saving.
Here is my savePlacementStudents method in controller.js.
$scope.selectedStudents = {};
$scope.savePlacementStudents = function(selectedStudents)
{
selectedStudents.selectedList = $scope.selection;
AdminPlacementService.savePlacementStudents(selectedStudents).then
(function(response)
{
if(response.data=="success"){
$window.scrollTo(0,0);
$scope.selectedStudents = {};
$scope.getplacementdetails($scope.currentPageIndex);
$scope.successmessage="Student Selection Saved!;
$timeout(function() {
$scope.successmessage="";
$scope.closeplacedcandidatespopup();
}, 1500);
}
});
}
Can anyone tell how can I pass respective placementId to this saveStudents method() so that I can set that placementId for those students selected.
Here is the solution.
The placementId passed to function placedcandidatespopup can be saved as follows in function placedcandidatespopup
$scope.selectedPlacementId = placementId;
Now the same $scope will have access in Popup also as it is using same controller.js. And now you can use this $scope.selectedPlacementId anywhere in controller.js
So you don't need to pass placementId...!!
Hope that would help you..!!
$scope.placedcandidatespopup = function(id)
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$scope.inserted = {
placementId:id,
};
var modalInstance = $uibModal.open({
templateUrl: 'views/test/myModal1.html',
controller: 'TestCntrl',
size: "Modelwidth",
resolve: {
items: function () {
return $scope.inserted;
}
}
});
}
In model you have to access using items.placementId and when you savePlacementStudents() method send placementId as well with student info.
I'm new in angular and I reeding A.Freeman's book "Pro Angular JS".
So I stuck in one of examples trying to understand why filter in ng-repeat is triggered.
Here is the code:
<body ng-controller="sportsStoreCtrl">
<div class="navbar navbar-inverse">
<a class="navbar-brand" href="#">SPORTS STORE</a>
</div>
<div class="panel panel-default row" ng-controller="productListCtrl">
<div class="col-xs-3">
<a ng-click="selectCategory()" class="btn btn-block btn-default btn-lg">Home</a>
<a ng-repeat="item in data.products | orderBy:'category' | unique:'category'" ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg">
{{item}}
</a>
</div>
<div class="col-xs-8">
<div class="well" ng-repeat="item in data.products | filter:categoryFilterFn">
<h3>
<strong>{{item.name}}</strong>
<span class="pull-right label label-primary">
{{item.price | currency}}
</span>
</h3>
<span class="lead">{{item.description}}</span>
</div>
</div>
</div>
</body>
and
angular.module("sportsStore")
.controller("productListCtrl", function ($scope, $filter) {
var selectedCategory = null;
$scope.selectCategory = function (newCategory) {
selectedCategory = newCategory;
}
$scope.categoryFilterFn = function (product) {
return selectedCategory == null ||
product.category == selectedCategory;
}
});
categoryFilterFn is one that confuses me. Why it's invoking when I press catefory buttons (with selectCategory() method on ng-click) since I never call categoryFilterFn explicitly?
Answering you question - because of $digest. You don't have call categoryFilterFn directly. Your selectedCategory has changed which is used in categoryFilterFn and categoryFilterFn is bound to scope.
Not sure how I can describe it correctly but here my explanation.
There are two "independent" parts :
The repeat iterate over an array of items.
If you select an category via ng-click function you set the new category in the scope.
Here kicks the filter function in, witch ties it up.
It is triggered because a new category is selected ($digest) and "reordering" the array (like map function in plain Javascript) and the angular magic (ng-repeat) displays only items with this category.
And that's the reason why I love angular so much 🤓
I'm simply trying to set up a warning dialog, and trying out Bootstrap modal for starters.
Bootstrap modal: http://getbootstrap.com/javascript/#modals
The modal fires but it does NOT show my modalTitle and modalBody values !
HTML snippet here (note the vm.modalTitle and vm.modalBody scope vars) -
<!-- Bootstrap Modal Dialog Template-->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel"><span ng-model="vm.modalTitle"></span></h4>
</div>
<div class="modal-body"><span ng-model="vm.modalBody"></span></div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
and my controller code :
vm.modalTitle = ''; vars initialized at the top of my controller
vm.modalBody = '';
...
function sendRequest(){
if (data.status == 'FAIL') {
if (data.messages.length > 0) {
logErr("Error submitting aggregation request: " + data.messages[0]);
vm.modalTitle = "Error submitting aggregation query !";
vm.modalBody = data.messages[0];
$('#myModal').modal('toggle');
$('#myModal').on('hide.bs.modal', function (e) {
// fired when modal is hidden from user
})
return;
}
}
}
The modal fires but it does NOT show my modalTitle and modalBody values !
I tried this route when I first learned Angular and very quickly got frustrated with the hacks that I had to do to get it to work. Your best bet is to use the AngularUI modal. It wraps the Bootstrap modal very nicely. http://angular-ui.github.io/bootstrap/.
I am not very experienced with angular and I just can't figure out why is my code behaving like this.. I have a controller, that gets data from a factory and a modal to display it. It returns the right data, according to the id it passes, but after on ng-repeat it loads the data for the first record only or nothing:
`
<div ng-controller="TokensCtrl">Get Tokens{{child.ChildId}}
<div id="tokensModal" class="modal fade tokens" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3>Tokens:</h3>
</div>
<div class="modal-body">
<ul ng-repeat='token in tokens'>
<li><input value={{token}} /></li>
</ul>{{tokens}} <!--the first record set of tokens on every iteration -->
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
</div>
</div>
the controller, that returns the right data:
app.controller('TokensCtrl',
function ($scope, tokens) {
$scope.status;
$scope.test = 'testing';
$scope.getTokens = function (id) {
console.log(id + "controller");
tokens.getTokens(id)
.success(function (tokens) {
$scope.tokens = tokens;
console.log($scope.tokens);// here i can see it returns the right set of tokens
})
.error(function (error) {
$scope.status = "Unable to get tokens: " + error.message;
})
}
}
)
`
I assume it might be some silly mistake, but I just can't see it.. or not
Try putting the ng-repeat directive in the li tag instead of ul.