AngularJs ngNotify dismiss on click - angularjs

I have been asked to add dismiss on click functionality to our notifications (which are served up by ngNotify). I thought this would be a simple task, but I cannot find this functionality by default.
At first I created a directive that targeted the class ngn-sticky. It was simply this:
angular.module('sapphire.directives').directive('ngnSticky', directive);
function directive(ngNotify) {
return {
restrict: 'C',
link: lnkFn
};
function lnkFn(scope, element, attrs, controller) {
element.on('click', function (e) {
ngNotify.dismiss();
e.preventDefault();
});
};
};
But this did not work. I added a button to the page with the notification and gave it the class ngn-sticky and that did work, but that was no the desired effect.
So, I though that maybe I can override the template like we do with angular-bootstrap, so I looked into the actual directive and found that it has no templateUrl to override.
Does anyone know how I can override the template? Or somehow add an onclick method to any ngNotify message?

Overriding the template is not a good solution, as you then implicitly depend on the internals of the external library!
Anyhow, in their source code you can see a template being put into the $templateCache.
function ngNotifyCache($templateCache) {
var html =
'<div class="ngn" ng-class="ngNotify.notifyClass">' +
'<span ng-if="ngNotify.notifyHtml" class="ngn-message" ng-bind-html="ngNotify.notifyMessage"></span>' + // Display HTML notifications.
'<span ng-if="!ngNotify.notifyHtml" class="ngn-message" ng-bind="ngNotify.notifyMessage"></span>' + // Display escaped notifications.
'<span ng-show="ngNotify.notifyButton" class="ngn-dismiss" ng-click="dismiss()">×</span>' +
'</div>';
$templateCache.put(TEMPLATE, html);
}
You should be able to override that by just putting in a new template with a the same key. Just the proper timing needs to be found out. The new template would need a ng-click attribute at the whole div I assume.
Source: https://docs.angularjs.org/api/ng/service/$templateCache, https://docs.angularjs.org/api/ng/type/$cacheFactory.Cache

Related

How to hook to "OnOpen" listener for uib-popover?

Context: I am using angular 1 and this UIB Popover control.
Since there is a text field in the popover template I called, my target is to focus on that text field whenever the popover is opened.
Unfortunately, there is no popover listener/event for "onOpen".
So I tried to do a
scope.$watch(()=>{return scope.isOpen}, (obj) ={
// where scope.isOpen is the local var in the popover-is-open
// expecting to write some code here to manipulate the element
// to realise the focus operation
// but there is no popover element yet when this is called
})
I was just wondering what other options I might have?
Thanks
I found nothing on the documentation talked about events and found this issue on the ui-bootstrap github stating that they do not support events nor do they ever plan to implement them. https://github.com/angular-ui/bootstrap/issues/5060
If you're looking for a different option that would give you access to the events would be to implement your own popover directive that simply wraps bootstrap popovers. In theory, they can function the same as the ui-bootstrap and allows you to tap directly into the events provided by bootstrap.
HTML
<div my-popover="Hello World" popover-title="Title" popover-shown="myCallback()">...</div>
JavaScript ('my-popover.directive.js')
angular
.module('myModule')
.directive('myPopover', myPopover);
function myPopover() {
return {
scope: {
popoverTitle: '#',
popoverShown: '&'
},
restrict: 'A',
link: function(scope, elem, attr) {
$(elem).popover({
title: scope.popoverTitle,
content: attr.myPopover
});
$(elem).on('shown.bs.popover', function () {
if(scope.popoverShown && typeof scope.popoverShown === 'function'){
scope.popoverShown();
}
});
}
};
}
Similar to uib-popover, you can add support for additional configurations by adding additional scoped properties.

AngularJs Directive don't update itself for source element's attribute updates

tried almost everything but not succeed.
I wanted to take an action only if I click on an element whose class name is "ion-android-favorite-outline".
My source element is like below
<i id="{{product.product_code}}" class="icon ion-android-favorite-outline"></i>
I am able to do it using "restrict:'C'" in the directive code.
In the directive, once I am done with data processing, I am changing source element's class to "ion-android-favorite" as below.
.directive(
"ionAndroidFavoriteOutline",
function(sessionStorageService, productService){
return{
restrict: 'C',
link: function(scope, element, attrs) {
element.bind("click" , function(e){
var productCode = attrs.id;
console.log(attrs.class); // on every click i get class name as 'ion-android-favorite-outline' event though html has class name as 'ion-android-favorite'
if (sessionStorageService.isLoggedIn()) {
productService.trackProduct(productCode).then(function(response){
if (response.data.status == "success") {
element.removeClass("ion-android-favorite-outline").addClass("ion-android-favorite");
} else {
element.removeClass("ion-android-favorite").addClass("ion-android-favorite-outline");
}
});
scope.$apply();
}
I can see source element's class name getting changed and its reflection in the UI as well.
However, if I again click on the source element (whose class is changed in previous click action ) still invokes the directive code.
Why ???
I tried scope.$apply , replace: true etc ... but no workaround.
Plz help.
You can use directive like below:
<i id="{{product.product_code}}" class="ion-android-favorite-outline" ion-android-favorite-outline></i>
#stephan, answered correctly.
element.unbind("click");

sanitize text input from textangular

I'm working with textangular as a rich text solution for a project I am working on.
It is required to sanitize this input because we only allow certain html tags.
Since this is not a default possibility of textangular I created a directive that wraps around the textangular directive. I can successfully sanitize the input text, but the view is never updated, and I have ran out of ideas how to achieve this
directive:
.directive('chTextAngular', function(){
return {
restrict: 'E',
require: 'ngModel',
template: function(elements, attributes) {
return '<div text-angular ng-model="' + attributes.ngModel + '" id="' + attributes.id + '"></div>';
},
link: function(scope, element, attributes, ngModel) {
scope.$watch(attributes.ngModel, function(n, o) {
if(n !== undefined) {
// Replace all the divs with <br> tags
var sanitized = ngModel.$viewValue.replace(/<div>/gm, '<br>').replace(/<\/div>/gm, ' ');
sanitized = sanitized.replace(/<p>/gm, '').replace(/<\/p>/gm, '<br><br>');
sanitized = $.htmlClean(sanitized, {
allowedTags: ["strong", "em", "ul", "ol", "li", "a", "b", "i", "br"],
allowedAttributes: ["a", "href"]
});
console.log(sanitized);
ngModel.$setViewValue(sanitized);
}
});
}
}
});
The log prints out the model and it shows that it is actually change. I just can not figure out how to update the actual textarea in textangular.
Can anyone help me with this, or put me in the right direction?
Ok, first question I have to ask is; do you really need the view to update or can it be fine as it is if the model is the correct data.
Second, you should probably be registering your function via ngModel.$parsers.push(function(n,o){...}) to avoid extra watchers.
The reason it's not updating is that we have a catch in textAngular to prevent the model from updating the view while someone is typing. If you do this while the field is focussed then you get an issue with the cursor moving back to the start/end of the text field. If you do want to update the view from the model then register an blur event handler (element.on('blur', ...);) and call scope.updateTaBindtaTextElement() may work depending on which scope your directive attaches to. If that function doesn't work you'll have to add a name attribute to your textAngular element and then use the textAngularManager.refreshEditor(name); function.

Dynamically change the action of href using angularjs

I'm a newbie to angular, and I'm playing around with it to try and understand how things work. I have an href as part of the template of a directive and an action associated with clicking the link. I would like to know how I can change the action when the user clicks on the link. I tried using a link function in my template, but I couldn't even get it to fire a message to the console.
Here is my link function:
var linkFunction = function(scope) {
scope.$watch(scope.loggedin, function() {
console.log('Here');
});
};
Any pointers? Or is there a better way.
TIA
Link function is part of directive. You can use an ng-click directive in the anchor tag in the template and provide its implementation in the linking function of the directive.
//template
Click Me
//Link function in directive
function(scope) {
scope.doThis = function() {
console.log("doing this);
}
}

Angular-UI-Bootstrap custom tooltip/popover with 2-way data-binding

I am using angular-ui-bootstrap in my current project, and I have a requirement for a popover that will allow the user to take some action on a given element (rename/edit/delete/etc...). Since angular-ui's bootstrap popover doesn't allow for custom html or data-binding by default, I have copied their tooltip/popover .provider and .directive in an effort to customize it to my needs.
Main Problem: The ng-click bindings are being lost after the popup is closed and re-opened.
Secondary Problem: Can two-way data-binding be setup so that I don't have to manually set scope.$parent.$parent.item?
Plunker: http://plnkr.co/edit/HP7lZt?p=preview
To give glance of what changes were made to the original tooltip.js:
The popover .directive is what has been modified the most:
.directive('iantooltipPopup', function () {
return {
restrict: 'E',
replace: true,
scope: { mediaid: '#', title: '=', content: '#', placement: '#', animation: '&', isOpen: '&' },
templateUrl: 'popover.html',
link: function (scope, element, attrs) {
scope.showForm = false;
scope.onRenameClick = function () {
console.log('onRenameClick()');
scope.showForm = true;
};
scope.onDoneClick = function () {
console.log('Title was changed to: ' + scope.title);
scope.showForm = false;
scope.$parent.$parent.item.title = scope.title;
scope.$parent.hide();
};
}
};
})
The tooltip .provider was only changed here, in an effort to get two-way binding to work on the title field :
var template =
'<'+ directiveName +'-popup '+
// removed
// 'title="'+startSym+'tt_title'+endSym+'" '+
'title="tt_title" ' +
'content="'+startSym+'tt_content'+endSym+'" '+
'placement="'+startSym+'tt_placement'+endSym+'" '+
'animation="tt_animation()" '+
'is-open="tt_isOpen"'+
'>'+
'</'+ directiveName +'-popup>';
I appreciate any help, I feel the compiled directives and providers seem to be large mental hurdles when getting started with Angular. I've been trying figure out and manipulate this directive so I can learn from it, just as much as actually needing the component itself.
Here is the working plunker
The problem is from the original tooltip. It removes the tooltip after you close but next time when you open it, it doesn't compile the tooltip again. (link function for the tooltip trigger only run in the first time.)
My approach is don't remove the tooltip, just control it by display attribute from CSS.
I also make a pull request to discuss this issue.
I just update the plunker.
The 2nd one is actually just make it link with the parent scope. However, it will create a child scope with my approach. I think you can use watch to do it as well.

Resources