Pass object to custom angular bootstrap ui tooltip - angularjs

Im trying to pass and object to a custom angular-ui bootstrap tooltip component.
My code so far is a new directive:
angular.module('ui.bootstrap.korv', [ 'ui.bootstrap.tooltip' ])
.directive('korvPopup', function () {
return {
restrict: 'EA',
replace: true,
scope: { title: '#', content: '#', placement: '#', animation: '&', isOpen: '&', species: '='},
templateUrl: 'korv.html'
};
})
.directive('korv', [ '$tooltip', function ($tooltip) {
return $tooltip('korv', 'korv', 'click');
}]);
and the the template:
<script type="text/ng-template" id="korv.html">
<div class="tooltip {{ placement }}" ng-class="{ in: isOpen(), fade: animation() }">
<div class="tooltip-arrow"></div>
<div class="tooltip-inner">obj is {{content}} obj.a is {{content.a}}</div>
</div>
and in the view:
<li korv="{a:1234}">
outputs:
obj is {a:1234} obj.a is
So the object I pass converts to a json string and I can not access its fields. Using tooltipHtmlUnsafe is not an option here.
I tried changing content: '#' to content: '=' but that doesn't work.
So how can I pass an object to tooltip?

This is not possible due to the implementation of angular bootstrap ui tooltip. My solution was to create a new directive:
angular.module('app').directive('speciesInfo', function ($log, $timeout) {
return {
restrict: 'A', // only activate on element attribute
scope: {
species: "=speciesInfo"
},
link: function (scope, elem, attrs) {
var showPromise;
elem.on('mouseenter', function () {
showPromise = $timeout(function () {
elem.children('.popover').show();
}, 500);
});
elem.on('mouseleave', function () {
$timeout.cancel(showPromise);
elem.children('.popover').hide();
});
},
templateUrl: 'species-info.html'
}
});
now it is easy to style the tooltip:
<div class="popover right in fade">
<div class="arrow"></div>
<div class="popover-inner">
<div class="popover-title text-center">
{{species.vernacularName}} <img class="small-species" ng-src="{{species.iconFileName}}"/>
</div>
<div class="popover-content">
<em> {{species.scientificName}}</em>
</div>
</div>

Related

Pass argument between parent and child directives

I have parent directive for navigation menu and child directives for menu links. Something like this:
<menu>
<menu-link />
<menu-link />
</menu>
In menu directive I use ng-translucent to be able to add html.
Is there any way to pass argument from menu to all menu-link elements?
For example, if:
<menu ng-disabled='true'..
I want all menu-link directives to get that value from parent.
One more thing: each menu-link have its own attributes, so it needs to have own scope.
You can make use of require, for more info read the angular directive doc.
Refer the example for more info:
angular.module('myApp', [])
.controller('MyController', MyController)
.controller('MyDirectiveController', MyDirectiveController)
.directive('myDirective', myDirective)
.directive('childDirective', childDirective)
function MyController($scope) {
}
function MyDirectiveController($scope) {
this.isDisabled = function() {
return $scope.disabled;
};
}
function myDirective() {
return {
restrict: 'E',
transclude: true,
template: '<div>myDirective Disabled: {{ disabled }}<ng-transclude></ng-transclude></div>',
scope: {
disabled: '=?ngDisabled'
},
controller: 'MyDirectiveController'
};
}
function childDirective() {
return {
restrict: 'E',
require: '^^myDirective',
template: '<div>childDirective disabled: {{ disabled }}</div>',
scope: {},
link: function(scope, elem, attrs, myDirectiveCtrl) {
scope.disabled = myDirectiveCtrl.isDisabled();
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController">
<my-directive ng-disabled="true">
<child-directive></child-directive>
<child-directive></child-directive>
</my-directive>
</div>
</div>

Angular1 Send Variable to directive

How can I send variable to directive? My code actually doesn't work, but I did everything from your comments :(
As you can see in my .html file, {{ ctrl.emptyParent.name }} is working.
.html
<div cms-dropdown emptyParent="emptyParent.name" classes="btn-default">
<i style="opacity: 0.8">{{ emptyParent.name }}</i>
</div>
directive
.directive('cmsDropdown', [function(){
return {
restrict: 'A',
scope: {
emptyParent: '=',
},
transclude: true,
template:
`
{{emptyParent}} Hi
`
link: function($scope, $element, $attrs){
}
};
}]);
and variable
this.emptyParent = {
_id: 'empty',
name: '~~#(brak)#~~',
parentAlbumId: null,
position: -1,
createdDate: undefined,
modifiedDate: undefined
};
change emptyParent="emptyParent.name" to empty-parent="emptyParent.name"
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.emptyParent = {"name":"jhon"}
})
.directive('cmsDropdown', [function(){
return {
restrict: 'A',
scope: {
emptyParent: '=',
},
transclude: true,
template:
`
{{emptyParent}} Hi
`,
link: function($scope, $element, $attrs){
}
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div cms-dropdown empty-parent="emptyParent.name" classes="btn-default">
<i style="opacity: 0.8">{{ emptyParent.name }}</i>
</div>
</div>

AngularJS custom directive - map isolate scope to new child scope

I created a custom directive for bootstrap alerts. My alerts display fine (hard code and data bind). Based on the alert type, I want display a unique header into my alert message based on the returned scope values (success, info, warning, danger). Currently I'm passing the type into <h1> but I don't want those values, they need to be custom.
<!-- data binding example -->
<trux-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</trux-alert>
<!-- hard coded example -->
<trux-alert close="close" type="warning">This is an important warning message!</trux-alert>
Inside my directive, the scope is isolated using scope: '#' (one-way)
.directive('truxAlert', function() {
return {
scope: {
type: '#',
close: '&'
},
replace: true,
transclude: true,
template:
'<div class="alert" '+
'ng-class="[\'alert-\' + (type || \'warning\'), closeable ? \'alert-dismissible\' : null]" '+
'role="alert">'+
'<button ng-show="closeable" '+
'type="button" class="close" '+
'ng-click="close({$event: $event})" '+
'data-dismiss="alert" aria-label="Close">'+
'<span aria-hidden="true">×</span>'+
'<span class="sr-only">Close</span>'+
'</button>'+
'<h1>{{type}}</h1>'+
'<div ng-transclude></div>'+
'</div>',
link: function (scope, element, attrs) {}
}
});
This would be easier if all my values were pulled through data binding, but I need to allow for manual hard coded option. I know with one-way isolated scopes '#' I can't change these values though DOM manipulation. I can't use '=' or '&' for two-way because the values are strings.
How do I solve for this problem?
My recommendation is have one attribute for the control the open/closed state of the directive's alert and another attribute for the dismiss handler function.
angular.module("myApp").directive('truxAlert', function() {
return {
scope: {
type: '#',
dismissHandler: '&',
title: '#',
open: '='
},
replace: true,
transclude: true,
template:
'<div class="alert" ng-show="open" '+
'ng-class="[\'alert-\' + type]" '+
'role="type">'+
'<button type="button" class="close" '+
'ng-click="truxClose($event)" '+
'data-dismiss="alert" aria-label="Close">'+
'<span aria-hidden="true">×</span>'+
'<span class="sr-only">Close</span>'+
'</button>'+
'<h1>{{title+" "+type}}</h1>'+
'<div ng-transclude></div>'+
'</div>',
link: function (scope, element, attrs) {
console.log("truxAlert linking");
if (!scope.type) { scope.type="warning" }
scope.truxClose = function(event) {
console.log("truxClose "+event);
if (attrs.dismissHandler) {
scope.dismissHandler({$event: event});
return;
}
scope.open = false;
};
}
};
});
The linking function of the directive determines if the dismiss-handler attribute exists and either invokes the dismiss handler or directly closes the alert.
The DEMO PLNKR show the directive being used both with an ng-repeat directive and in a standalone manner.
Maybe, i don't understand you question.
You want to do so jsfiddle?
<form name="ExampleForm" id="ExampleForm">
<span simple="{{val}}">{{val}} - value from data-binding </span>
<br>
<span simple="valueTwo">valueTwo - hard code value</span>
</form>
And js controller
.controller('ExampleController', function($scope, $rootScope, $alert) {
$scope.val = "valueOne";})
And js directive
.directive('simple', function() {
return {
restrinct: 'A',
scope: {
simple: "#"
},
link: function(scope) {
console.log(scope.simple, typeof(scope.simple));
}
}})
UPDATED
angular.module('ExampleApp', ['use', 'ngMessages'])
.controller('ExampleOneController', function($scope) {
$scope.val = "valueOne";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.controller('ExampleTwoController', function($scope) {
$scope.val = "valueTwo";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.controller('ExampleThreeController', function($scope) {
$scope.val = "valueThree";
$scope.$on('pass.from.directive', function(event, value) {
$scope.valFromDirective = value;
});
})
.directive('simple', function($interval) {
return {
restrinct: 'A',
scope: {
simple: "#"
},
link: function(scope) {
var i = 0;
$interval(function() {
i++;
scope.$emit('pass.from.directive', scope.simple + i);
}, 1000);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleOneController">
<h3>
ExampleOneController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
<div ng-controller="ExampleTwoController">
<h3>
ExampleTwoController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
<div ng-controller="ExampleThreeController">
<h3>
ExampleThreeController
</h3>
<form name="ExampleForm" id="ExampleForm">
<div simple="{{val}}">{{val}} - value from scope </div>
<div>{{valFromDirective}} - value from directive </div>
</form>
</div>
</div>

Angular directive scope - template include vs inline transclude

I have an angular directive for displaying a modal window. It can accept the contents either inline between the HTML tags, or be pointed to a template. When using this directive I seem to have normal access to the $scope when I am using the transcluded inline version of this directive, but when I use a template I do not.
What am I missing here? I've made a smaller sample directive that has the same behavior.
Demo: http://fiddle.jshell.net/ahezfaxj/2
Inline Content Usage
<ang-test show="showBoolean">
<p>Content here!</p>
</ang-test>
Template Usage
<ang-test show="showBoolean" template="'myTemplate.html'"></ang-test>
Directive
app.directive("angTest", function () {
return {
template: function () {
return "<div class='test-container'>" +
" <div ng-if='show && template' ng-include='template'></div>" +
" <div ng-if='show && !template' ng-transclude></div>" +
"</div>";
},
restrict: "E",
replace: true,
transclude: true,
scope: {
template: "#",
show: "="
},
link: function ($scope, $element, attrs) {
if(value){
$element[0].style.display="block";
}else{
$element[0].style.display="none";
}
}
};
});
Please see demo below. You created isolated scope in your directive thus your directive scope is not this same as controller $scope. But you can add as well thing to your directive scope like in example below.
I hope that will help.
var app = angular.module("app", []);
app.controller("BaseCtrl", function ($scope) {
$scope.thing = "Hello!";
$scope.showOne=false;
$scope.showTwo=false;
});
app.directive("angTest", function () {
return {
template: function () {
return "<div class='test-container'>" +
" <div ng-if='show && template' ng-include='template'></div>" +
" <div ng-if='show && !template' ng-transclude></div>" +
"</div>";
},
restrict: "E",
replace: true,
transclude: true,
scope: {
template: "#",
show: "=",
thing:'#'
},
link: function ($scope, $element, attrs) {
//Show/hide when `show` changes
$scope.$watch("show", function (value) {
if(value){
$element[0].style.display="block";
}else{
$element[0].style.display="none";
}
});
}
};
});
.test-container{
padding:5px;
background: #EEE;
}
.transcluded {
color:red
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="BaseCtrl">
Outside Directive: <strong>{{thing}}</strong>
<hr />
<button type="button" ng-click="showOne=!showOne">Toggle One</button>
<ang-test show="showOne">
<p class="transcluded">Inside Included Directive: <strong>--> thing transcluded-->{{thing}}</strong></p>
</ang-test>
<hr />
<script type="text/ng-template" id="myTemplate">
<p>Inside Template Directive: <strong>thing from directive scope -->{{thing}}</strong></p>
</script>
<button type="button" ng-click="showTwo=!showTwo" >Toggle Two</button>
<ang-test show="showTwo" template="myTemplate" thing="{{thing}}"></ang-test>
</div>
</div>

Angularjs Directive finding element inside ngIf

I have created a angularjs directive that are supposed to display an address.
$(elem).find('button').length
now return the correct value but it have been called a hack and is there a better way to do it. I understand that ngIf creates a child scope and the button element isn't available when my link code runs if I don't wrap it in $timeout.
So what is the pretty way to access the element inside my ngIf without the $timeout hack?
My Directive
angular.module('directives')
.directive('addresss', ['$timeout', function ($timeout) {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template........ ',
link: function(scope,elem,attr){
$timeout(function(){
console.log($(elem).find('button').length);
})
}
};
}]);
Template for address directive
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button class="btn-link">Delete</button>
</div>
</div>
if all you want to bind a click event you could just put a ng-click in the button:
JS:
app.directive('address', [function () {
return {
restrict: 'AE',
scope: {
address: '='
},
templateUrl: 'template.html ',
link: function(scope,elem,attr){
scope.myClickHandler = function() {
console.log('button clicked');
});
}
};
Template:
<div class="spacer">
<h1>Address</h1>
<div>
<strong>{{address.name}}</strong>
</div>
<div ng-if="address.name">
<button ng-click="myClickHandler()" class="btn-link">Delete</button>
</div>
</div>
Try this (if I get well your question)
html
<div data-ng-controller="MainController">
<div data-my-dir address="address"></div>
</div>
js
angular.module('myApp', [])
.controller('MainController',function($scope) {
$scope.address = {
name : 'myname'
};
})
.directive("myDir", function () {
return {
scope:{
address: '=',
},
template:'<button class="btn-link" ng-if="address.name">Delete</button>',
link: function (scope, elem) {
console.log(scope.address.name);
}
}
});

Resources