Angularjs adding directive on click - angularjs

i have table that has this body
<tbody >
<tr ng-repeat="con in mycon | array | filter:search | orderBy:predicate:reverse"
ng-click="showhistory($event,con.conid)">
<td >{{ con.fname }}</td>
<td >{{ con.lname }}</td>
</tr>
</tbody>
When the row is click i call this function my my controller
$scope.showhistory = function ($event,cid) {
$event.stopPropagation();
var contentTr = angular.element('<con_history ></con_history>');
contentTr.insertAfter(angular.element($event.target).parent());
$compile(contentTr)($scope);
$scope.$apply
};
And i can see that the con_history tags get added. But it doesn't render the directive. When I add the directive i do not see BLAH BLAH , I only see the con_history tag
this is my directive
app.directive('con_history', function() {
return {
restrict: 'AE',
replace: 'true',
template: '<tr><td colspan="11">BLAH BLAH</td></tr>'
};
});
thanks for any help

You are not doing it in angular way, I think this is what you want to do:
<tr ng-repeat="con in mycon | array | filter:search | orderBy:predicate:reverse"
ng-click="showhistory($event,con.conid)">
<td >{{ con.fname }}</td>
<td >{{ con.lname }}</td>
</tr>
<con_history ng-if="historyVisible[con.conid]"></con_history>
in your controller
$scope.historyVisible = {};
$scope.showhistory = function ($event,cid) {
.
.
$scope.historyVisible[cid] = true;
.
.
};

Related

Angular directive with no template - assign ng-click function from directive

How can I set the ng-click function on the element where my directive attribute is applied? After having issues with my directive template, because it spans multiple tr's, I resulted to using ng-repeat-start/end i.e., no template. So, my question is: what is the proper way to get the contents of the directive element into the isolate scope of the directive, so I can assign values/functions to it, as if it were the template?
// controller scope
<tr campaign-item ng-repeat-start="campaign in vm.allCampaigns.results | orderBy:vm.params.sort:vm.sortReverse track by $index" ng-if="vm.allCampaigns.totalCount > 0" campaign="campaign" close-preview="vm.hideCampaignPreview()" class="campaign-tr" id="campaign-{{campaign.id}}" ng-class="{'selected': showCampaignDetails}" user-role="{{vm.user.role}}" campaign-options="" campaign-detail="" show-campaign-details="">
<td>{{ campaign.name }}</td>
<td>{{ campaign.priority }}</td>
<td>{{ campaign.status }}</td>
<td>{{ campaign.createdBy }}</td>
<td>{{ campaign.approvedBy }}</td>
<td ng-show="item.releaseDate">{{ campaign.releaseDate * 1000 | date:'short' || ''}}</td>
<td ng-show="!item.releaseDate"></td>
<td ng-show="item.expirationDate">{{ campaign.expirationDate * 1000 | date:'short' }}</td>
<td ng-show="!item.expirationDate"></td>
<td>
<select id="campaign-options" name="campaignOptions" class="form-control" ng-model="selectedCampaignOption" ng-options="option for option in campaignOptions track by $index">
</select>
</td>
</tr>
<tr class="campaign-description campaign-{{campaign.id}}" ng-show="showCampaignDetails" ng-class="{'selected': showCampaignDetails}">
<td colspan="8">
<p> {{ campaignDetails.description }}</p>
</td>
</tr>
// directive
angular.module('fotaAdminPortal')
.directive('campaignItem', ['vsmsCampaignFactory', function (vsmsCampaignFactory) {
return {
restrict: 'A',
transclude: true,
scope: {
campaign: '=',
closePreview: '&',
userRole: '#',
campaignOptions: '=?',
showPreview: '=?',
showCampaignDetails: '=?',
campaignDetail: '=?'
},
// templateUrl: 'app/vsms/admin/campaign/campaign.tpl.html',
link: function(scope, element, attr, ctrl, transclude) {
scope.showCampaignDetails = false;
transclude(scope, function(clone) {
element.append(clone);
element[0].addEventListener('click', function(e) {
if(e.target.id == 'campaign-options') {
return;
} else {
vsmsCampaignFactory.getCampaign(scope.campaign.id)
.then(function(response) {
scope.showCampaignDetails = true;
scope.campaignDetails = response;
console.log(scope);
});
}
})
});
...
You might add ng-click from directive like so: (If you'd provide a fiddle or plnkr would be easier for us to test)
element.attr("ng-click", "onClick()");
If you have the onClick() function on controller add controllerName.onClick()
element.attr("ng-click", "vm.onClick()");
Then at the end
$compile(element.contents())(scope);
or
$compile(element)(scope);
Another option is
element.bind('click', function(e) {
// Handle onclick event here.
});

angular hide when !element clicked

I'm rendering some td's inside a ng-repeated tr with a directive attribute. For each iteration there are two tr's, the second is initially hidden, until the user clicks the first tr. The revealed tr is correctly hidden when another tr is clicked. However, I need the revealed tr to be hidden when clicking anywhere outside the currently displayed tr's, not just other tr's. This isn't working in my directive because each time a click event is fired the documentClickHandler function is evaluated for each ng-repeat iteration i.e., the first eventOutsideTarget may evaluate to true but the others are false, so the closePreview() function is always called. Any ideas?
<tr ng-repeat-start="campaign in vm.campaignData track by campaign.id" ng-click="vm.showCampaignPreview(campaign)" campaign-item campaign="campaign" campaign-options="vm.campaignOptions" close-preview="vm.hideCampaignPreview()">
</tr>
<tr ng-class-odd="'odd'" ng-class-even="'even'" ng-repeat-end ng-show="vm.selectedCampaign.id == campaign.id">
<td colspan="8">{{ campaign.description }}</td>
</tr>
// directive
(function(){
'use strict';
angular.module('campaignApp')
.directive('campaignItem', ['$document', "$parse", function ($document, $parse) {
return {
restrict: 'A',
scope: {
campaign: '=',
campaignOptions: '=',
closePreview: '&'
},
controller: 'vsmsCampaignsController',
templateUrl: 'campaign.tpl.html',
link: function(scope, element, attr, controller) {
var documentClickHandler = function (event) {
var eventOutsideTarget = (element[0] !== event.target.parentElement) && (0 === element.find(event.target.parentElement).length);
if (eventOutsideTarget) {
scope.$apply(function () {
scope.closePreview();
console.log('close preview');
});
}
};
$document.on("click", documentClickHandler);
scope.$on("$destroy", function () {
$document.off("click", documentClickHandler);
});
}
};
}]);
})();
// campaign.tpl.html
<td>{{ campaign.name }}</td>
<td>{{ campaign.priority }}</td>
<td>{{ campaign.status }}</td>
<td>{{ campaign.createdBy }}</td>
<td>{{ campaign.approvedBy }}</td>
<td>{{ campaign.releaseDate * 1000 | date:'short' }}</td>
<td>{{ campaign.expirationDate * 1000 | date:'short' }}</td>
<td>
<select ng-init="selectedOption = campaignOptions[0]" name="campaignOption" class="form-control" ng-model="selectedOption" ng-options="option.name for option in campaignOptions track by option.value">
</select>
</td>

Angular custom directive execute after inner ng-repeat finished

My angular template is:
<div style="min-width: 500px;">
<table sticky-table>
<thead>
<tr>
<th>Size</th>
<th>Vertical</th>
<th>Choker</th>
<th>Basket</th>
<th>Basket at 60</th>
<th>Basket at 45</th>
<th>Basket at 30</th>
</tr>
</thead>
<tbody ng-repeat="row in getWireRopeSlingCapacityData(metricUnit)">
<tr>
<th>{{ row.size }}</th>
<td>{{ row.vertical }}</td>
<td>{{ row.choker }}</td>
<td>{{ row.basket }}</td>
<td>{{ row.basket_60 }}</td>
<td>{{ row.basket_45 }}</td>
<td>{{ row.basket_30 }}</td>
</tr>
</tbody>
</table>
</div>
I need a custom directive 'sticky-table' that will apply some jquery on the table. My issue is that the body of table element is not populated when directive executes. My directive code is:
app.directive("stickyTable", function($parse, $timeout) {
var stickyTable = function(element){
... aplly jquery code on table element
... table element inner html is: "
<thead>
<tr>
<th>Size</th>
<th>Vertical</th>
<th>Choker</th>
<th>Basket</th>
<th>Basket at 60</th>
<th>Basket at 45</th>
<th>Basket at 30</th>
</tr>
</thead>
<!-- ngRepeat: row in getWireRopeSlingCapacityData(metricUnit) -->
"
};
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
var result = stickyTable(element);
scope.$on('scroll1Position', function(event, position) {
//console.log('Got scrolled to: ' + position.top + 'x' + position.left);
if (!result)
return;
result.repositionHead(position);
result.repositionColumn(position);
});
}
}
});
Be sure to specify the priority of your directive. Ng-repeat gets set to a default priority of 1000, so you need to set a higher priority than that for this directive to be compiled first. See the example below:
app.directive("stickyTable", function($parse, $timeout) {
...
return {
prioriy: 1001
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
var result = stickyTable(element);
scope.$on('scroll1Position', function(event, position) {
//console.log('Got scrolled to: ' + position.top + 'x' + position.left);
if (!result)
return;
result.repositionHead(position);
result.repositionColumn(position);
});
}
}});
You can view the directive documentation for more details.

angularjs ng-repeat with Filter or ng-if condition

I want to render text if it is Name or Value. I don't want to loop if it is createdate or enventId. I'm trying with Filter and ng-if condition. It is not working.
HTML CODE
<tr ng-repeat="event in events | filter:Name ">
<td >{{event.Name}} : </td>
<td>{{ event.Value }}</td>
</tr>
JS CODE
Events: [
{
CreatedTime: "/Date(1420757322810-0800)/",
EventId: 13,
Name: "AdGroupId",
Value: "2367898"
},
{
CreatedTime: "/Date(1420757322810-0800)/",
EventId: 13,
Name: "AdGroupId",
Value: "2367898"
}
]
I expect the result should be
AdGroupId :2367898
Assuming that what you are trying to ask is how to exclude items with neither a name nor a value, you'll need a custom function for this. This should suffice:
$scope.filterEvents = function(e){
return e.Name || e.Value;
};
And then:
<tr ng-repeat="event in events | filter:filterEvents">
<td >{{event.Name}} : </td>
<td>{{ event.Value }}</td>
</tr>
Example
Alternatively, if you are saying you want to filter the values based on a specified name and/or value, you can do so like this:
$scope.filterEvents = function (e) {
return ($scope.Name || $scope.Value) &&
(!$scope.Name || $scope.Name === e.Name) &&
(!$scope.Value || $scope.Value === e.Value);
};
(HTML is same as above)
Example
Assuming you are looking for a filter to cut out the Events that has no Name and Value properties in it.
Here is a sample for you:
Controller:
$scope.filterNameValue = function(e){
if(angular.isDefined(e.Name) && angular.isDefined(e.Value))
return e;
};
Html
<table>
<tbody>
<tr ng-repeat="event in events | filter: filterNameValue">
<td >{{event.Name}} : </td>
<td>{{ event.Value }}</td>
</tr>
</tbody>
</table>
Working Sample here

Can Angular ng-if check if the value contains something?

I got the following in my template:
<td ng-if="invoice.paymentMethod == 'automatic'">{{ invoice.paid | date:'yyyy-MM-dd hh:ss' }}</td>
<td ng-if="invoice.paymentMethod != 'automatic'">{{ invoice.paid | date:'yyyy-MM-dd' }}</td>
It shows the payment date in a different formate (with time) when the the payment was made automatically.
But: in the future, this "invoice.paymentMethod" can become something like "automatic - ideal" or "automatic - paypal".
So, can't I make a ng-if so that it checks if invoice.paymentMethod CONTAINS "automatic" instead of be equal to it? Should be easy but I can't find it anywhere.
In that case ngSwitch will works perfectly please see documention here
https://docs.angularjs.org/api/ng/directive/ngSwitch
or see that demo: http://jsbin.com/qejoza/1/edit or here http://jsbin.com/qejoza/2/edit
HTML:
<table ng-repeat="invoice in invoices" ng-switch on="invoice.paymentMethod">
<tr>
<td ng-switch-when="automatic">automatic: {{ invoice.paid | date:'yyyy-MM-dd hh:ss' }}</td>
<td ng-switch-when="automatic-ebay">ebay: {{ invoice.paid | date:'yyyy-MM-dd hh:ss' }}</td>
<td ng-switch-when="automatic-paypal">paypal:{{ invoice.paid | date:'yyyy-MM-dd hh:ss' }}</td>
</tr>
<table>
JS:
var app = angular.module('app', []);
app.controller('firstCtrl', function($scope){
$scope.invoices=[{
paymentMethod: 'automatic-paypal',
paid: "16/01/2014"
},
{
paymentMethod: 'automatic-ebay',
paid: "16/01/2014"
},
{
paymentMethod: 'automatic',
paid: "16/01/2014"
}];
});

Resources