Angular JS not rendering in ng-click - angularjs

I'm building a MEAN stack app for tracking courses, grades, and assignments. I'm trying to generate delete buttons for courses in my index view. All the expressions render correctly except for course._id in the following table. It is referred to within an ng-click value, so is not braced.
<tbody>
<tr ng-repeat="course in courseData">
<td>{{course.name}}</td>
<td>{{course.courseNum}}</td>
<td>{{course.students.length}}</td>
<td>
<ul ng-repeat="comment in course.comments">
<li>{{comment}}</li>
</ul>
</td>
<td>
<button type="button" class="btn btn-danger" ng-click="remove(course._id)">Delete</button>
</td>
</tr>
</tbody>
The remove function is very straightforward. It sends a delete call to the API and renders the index state again.
$scope.remove = function (courseId) {
$http.delete("/api/courses/" + courseId);
$state.go('courseState');
};
It seems like I'm probably missing something simple. Course._id will render outside the ng-click with the curly braces, but the braces can't be used in the ng-click attribute.
Most of the solutions I've found were all about creating directives, but getting that value inside the ng-click attribute should be as simple as just passing course._id as the argument.

Related

Ng-click does not work outside of my tr tag AngularJS

I am working on an app and I cant seem to figure out why my ng-click only works inside of my (single) tr tag but as soon as I put it into another tr tag it stop working. Keep in mind it was working before I used the ng-repeat within the first tr tag. Here is what my code looks like, any advice would greatly help!
<table>
<tbody>
<tr>
<td ng-click="commentOpen = !commentOpen">
<div class="iconsize">Comment Closed</div>
</td>
<td ng-click="switchOpen = !switchOpen">
<div class="iconsize">Switch Closed</div>
</td>
</tr>
<tr>
<td>
<div ng-show="commentOpen == true">
<textarea>Comment Open</textarea>
</div>
<div ng-show="switchOpen == true">
<p>Switch On</p>
</div>
</td>
</tr>
</tbody>
</table>
I had the ng-repeat on the tag which was causing my ng-click to not fire. I ended up moving my ng-repeat to the tbody and the ng-click and ng-show started working again.
ngRepeat creates new scopes for its children, it just usually seems like it's accessing the same scope because this new scope inherits from its parent.
Meaning, commentOpen is actually referring to a property on the wrong scope.
Below are three potential ways for you to fix this:
1) controller as, and always refer to the controller you're after by name
2) $parent.commentOpen (Don't do this! It becomes very confusing as you nest)
3) Instead of commentOpen and switchOpen, you can use an Object (e.g. $scope.openControls = { comment: false, switch: false }, and then in the td tags you would write something like ng-click='openControls.comment = !openControls.comment'). This way it's passed inherited by reference (where as a boolean would be by value), and keeps synced.

ng-hide or ng-show does not work if its controlled from within a ng-repeat

I am trying to hide the div if any of the buttons in the ng-repeat is clicked. However it doesn't seem to work, it leads me to think if ng-hide or ng-show won't work if it is controlled from within a ng-repeat?
<div data-ng-hide="showChooseHardware">
<table class="table">
<tbody>
<tr data-ng-repeat="hardware in hardwares">
<td>{{hardware.name}}</td>
<td>
<button type="button" class="btn" data-ng-click="showChooseHardware=!showChooseHardware"/>
</td>
</tr>
</tbody>
</table>
</div>
This is due to the fact that ng-repeat creates a new scope for each template and due to how prototypal inheritance works in JavaScript (and AngularJS).
Use an object:
$scope.viewModel = { showChooseHardware: false };
HTML:
data-ng-hide="viewModel.showChooseHardware"
And:
data-ng-click="viewModel.showChooseHardware=!viewModel.showChooseHardware"
A great explanation on the issue can be found here.
I recommend using ng-showinstead in this case since the variable is called showChooseHardware.
ngRepeat directive creates new scope in every iteration,for every item in array.It can make a problem,which you have.

ngIf inside ngRepeat not working inside <table> when controller defined with string

I have an ng-if inside an ng-repeat in a template, and the ng-if is not working, even if I change it to just
ng-if="false"
I can make it work by adding
ng-controller="TemplateController"
to a parent div, however when I do this, my controller cannot receive resolved arguments:
resolve: {
myVar: function() {
return "hello world";
}
}
Unknown provider: myVarProvider <- myVar
if I remove the ng-controller, and add
controller: "TemplateController"
after my resolve:, then myVar is passed successfully, however ng-if no longer works
my HTML:
<table>
<div ng-repeat=“row in rows"><tr>
<span ng-if=“row.active==1">
<td>{{row.data}}</td>
<td></td>
<td>{{ row.date | date:"MM/dd/yyyy"}}</td>
<td>
<a href=“stuff”>click me</a>
</td>
</span>
<span ng-if=“row.active > 1">
<td>{{row.otherData}}</td>
<td>{{row.str}}</td>
<td>{{ row.date | date:"MM/dd/yyyy"}}</td>
<td>
<a href=“stuff”>click me instead</a>
</td>
</span></tr>
</div>
</table>
right now, I get a whole bunch of blank cells, and both 'click me' links.
if I remove the tags, it works, but it's not in a table
moreover, not only is the ng-if not working, but any variables I reference inside {{}} are being replaced with blanks (but they also work if is removed)
jsFiddle: http://jsfiddle.net/Mh2UH/1/
The golden rule to avoid this problem is
Always have a dot in your angular bindings
ng-if="false"
Does not have a dot. Therefore the value false is being passed to the scope of the ng-if but can't be updated, since false is an immutable boolean value.
The correct way,
ng-if=status.enabled
Where status is an object.

update ng-repeat item's data inside ng-repeat at click

I’m having my first steps with angularjs framework, and I’m not understanding how I can update my second ng-repeat data inside each of the first’s item ng-repeat only when a user click on it (lazy loading).
<table class="table table-striped table-hover">
<tbody ng-repeat="customer in customers">
<tr>
<td>
<button ng-click="loadInvoices(customer); showDetails = !showDetails;" type="button" class="btn btn-default btn-xs">
</td>
<td>{{customer.ClientId}}</td>
</tr>
<tr ng-show="showDetails">
<td>
<table class="table table-striped table-hover">
<tbody ng-repeat="invoice in invoices">
<tr>
<td>{{invoice.Id}}</td>
</tr>
</tbody>
</table>
</td>
</tr><!--showDetails-->
</tbody><!--.customer-->
</table>
How can I achieve it? Thanks for your help! :)
You can do something like this:
<button ng-click="loadInvoices(customer);" type="button" class="btn btn-default btn- xs">Invoces</button>
and in controller:
$scope.loadInvoices = function(customer) {
if (this.showDetails = !this.showDetails) {
if (!this.invoices) {
// Load invoices for current customer (probably using service)
Customer.loadInvoices(customer.ClientId).then(function(invoices) {
customer.invoices = invoices;
});
}
}
}
By checking if (!this.invoices) {...} (this points to the current customer scope) you make sure that current customer doesn't have loaded invoices yet and you need to load them. On subsequent button clicks customer.invoices is going to be already available and you will not load data again.
I also added an example how using Customer service would fit into this workflow.
View demo: http://plnkr.co/edit/LerBd9ZTPLwhp8JZ6xwU?p=preview
With the ng-controller directive
Simply use the ng-controller directive to tell that a customer scope will be managed by an instance of the controller you pass in.
With a custom directive
Typical design for this: a customer directive with a customer controller which manages the scope of one customer.
The keys are:
ng-repeat creates child scopes
add a directive to attach a controller to each of those scopes
you can now manage each customer scope independently.
The controller, in both cases
This controller will hold loadInvoices which will attach the invoices array to the customer scope.
Why a custom directive ? You will also be able to have a separate template for a customer, specific pre link and post link functions, etc.
Why a customer specific controller since scope inheritance will enable the loadInvoices context to be the customer specific scope ? Extensibility, testability, decoupling.

Why my ng-show doesn't work?

I have the following code :
<div ng-init="showDetail = false">
<table>
<tbody>
<tr ng-repeat="dataTable in arrayTableData">
<td ng-repeat="data in dataTable.data" ng-click="showDetail = true;">{{data}}</td>
</tr>
</tbody>
</table>
<div ng-show="showDetail">
<button ng-click="showDetail = false">Close</button>
</div>
</div>
My variable showDetail changes value when you click on a data of the table, but my div showDetailCell not appear.
If I change the initialisation of showDetail with true the detail appear and disappear when you click on the button, but the click on the cell doesn't display showDetailCell.
ng-repeat will get its own scope. Due to Javascript inheritance, whenever variable from parent object is assigned in child scope will create new variable. It will no more reference to parent object variable. Better use . notation in the scope variable.
Instead of showDetail, use detail.toggle will solve the problem.

Resources