Can't invoke action on the button inside ng-repeat directive - angularjs

I'm new to AngularJS, and while playing with it, i have encountered with the problem.... I have a table like this :
...
<tr ng-repeat="line in lines">
<remove-line>
<input id="line_id" type="hidden" value="{{line.id}}">
<td id="sn">{{$index+1}}</td>
<td>{{line.ref}}</td>
<td>{{line.label}}</td>
<td class="tva">{{line.tva}}</td>
<td class="qty">{{line.qty}}</td>
<td class="unity">{{line.unity}}</td>
<td class="prix">{{line.prix}}</td>
<td>{{line.prix*line.qty}}</td>
<td><button class="btn" id= "remove"><i class="icon-remove"></i> </button></td>
</remove-line>
</tr>
...
I want to have some behavior when clicking on the remove button, using custom directive. AngularJS code looks like :
angular.module('myApp', []).directive('removeLine',function(){
var remove = function(){
...
alert ("Oops removed!");
}
return {
restrict: 'E',
link : function(scope,element, attrs){
$("#remove").on('click', remove);
}
};
});
But this doesn't work.... Nothing happens when i click on the remove button in the table..... But all this work fine when the button is out of the tag. Why is it so and how make it work?
I have created jsfiddle to illustrate my situation http://jsfiddle.net/alexrussinov/cs8RP/71/. What is strange that when I test this code on my local machine buttons in the table don't work but two separate under it, work fine. On jsfiddle, neither in the table nor below it, it doesn't work.

You can't have multiple elements on a page with the same ID, which is what you're doing with the button.
I think the simplest solution would be to stick the remove() call directly in the button tag with ng-click, passing in the line that you wish to remove. This of course assumes that your remove() method is part of $scope.
<button class="btn" ng-click="remove(line)"><i class="icon-remove"></i></button>

Related

Calling a function on an element inside xeditable form

I have an x-editable form with several fields in it. I've only show the checkbox field here for brevity. There is an edit button that opens all of the elements for editing and when I click submit all of the elements are saved. While in edit mode I want to be able to call a function when the checkbox is clicked before submitting the form. It will be for validation to make sure the user really wants to uncheck the box. I want to prevent the default behavior of the checkbox and display a dialog for confirmation. This is simple with a regular checkbox but I can figure out how to do it with x-editable . ng-click doesnt seem to work. As you can see from the example e-onClick works but only with built in functions like alert() and console.log().
<form editable-form name="tableform" onaftersave="save()"oncancel="cancel()">
<table>
<tr>
<th>Active:</th>
<td>
<span editable-checkbox="user.active" e-form="tableform" e-onClick="console.log('test')"> {{user.active)}}
</span>
</td>
</tr>
</table>
</form>
I want to do some thing like this:
<span editable-checkbox="user.active" e-form="tableform" e-onClick="confirm($event)"> {{user.active)}}
</span>
and in my controller do something like this:
$scope.confirm = function($event){
$event.preventDefault();
// show confirmation code
};
Can you try
<span editable-checkbox="user.active" e-form="tableform" e-ng-click="confirm()"> {{user.active)}}</span>
And
$scope.confirm = function(){
console.log("test")
};
This will work

Angular JS not rendering in ng-click

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.

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.

Angular UI-Router ui-sref ignore some elements

I have an interesting problem with the uiSref directive and I haven't been able to find a solution (well an elegant one anyway) anywhere on the web. Basically I have a requirement from a client to be able to click a row in a table of resources and go to the editing view for that resource. Normally the uiSref directive works beautifully, but the problem resides in the fact that I have a Bootstrap dropdown in the last <td> of the table with a bunch of quick actions in it. The HTML looks something like this:
<table class="table table-bordedered table-hover">
<thead>
<tr>
<td>Name</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="resource in resources" ui-sref="edit({id: resource.id})">
<td ng-bind="resource.name"></td>
<td class="actions-column">
<div class="btn btn-xs btn-default" data-toggle="dropdown">
<i class="fa fa-cog"></i>
</div>
<ul class="dropdown-menu pull-right">
<li>
SOMETHING CRAZY
</li>
</ul>
</td>
</tr>
</tbody>
</table>
The problem is that when I click on the button in the actions column, the uiSref overrides the default action of the dropdown and takes me to the edit page. Now you might be asking yourself "well that's easy, why can't you just stop the propagation of the event!?"... doesn't work. When I add this to the actions column:
<td class="actions-column" ng-click="$event.stopPropagation()">
It kills the functionality of the dropdown menu and nothing shows up. Right now I have a workaround in place where I define an ngClick on the <tr> element that then deciphers where the state should go depending on the element clicked like so:
<tr ng-repeat="resource in resources" ng-click="goToEdit(resource, $event)">
And The JS looks like this:
scope.goToEdit = function(resource, event) {
// if the event.target has parent '.actions-column' or is that column, do nothing else
// invoke $state.go('edit', {id: resource.id})
}
I hate it though and I have a lot of list views like this. All I'm looking for is an elegant and portable solution that hopefully works natively through UI Router like $event.stopPropagation() (Although I've poked through the UI Router source and can't seem to find a workable alternative). Basically I want to have my cake and eat it too. Anyway, it'll be interesting to see what the SO community can come up with or if what I'm asking for is not currently possible. Thanks!
I got it! While looking through the UI Router source some more, it appears that the click event will be ignored if the target attribute is populated on the element that the uiSref resides on. It may not be the most beautiful thing in the world, but it sure is easier than what I was doing before.
NOTE: This only works if you're using the whole jQuery library, not jQLite
So I wrote this directive:
app.directive('uiSrefIgnore', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.on('click', function(e) {
// Find the ui sref parent
var uiSref = elem.parents('[ui-sref]').first();
// Set the target attribute so that the click event is ignored
uiSref.attr({
target: 'true'
});
// Function to remove the target attribute pushed to the bottom
// of the event loop. This allows for a digest cycle to be run
// and the uiSref element will be evaluated while the attribute
// is populated
setTimeout(function() {
uiSref.attr({
target: null
});
}, 0);
});
}
};
});
That way, whenever I want to ignore the javascript event for just the uiSref directive, I can just add this to the html:
<tr ui-sref="edit">
<!-- any other elements -->
<td ui-sref-ignore>The element I care about</td>
</tr>
BOOM! Let me know what you guys think about the implications of this.

Resources