Directive That Injects a Modal $on Event in AngularJS - angularjs

How do I create a directive that injects a fixed position modal or a directly underneath the element that the directive is attached to? So in the directive I would want scope.$on to trigger injecting directly below the element.
Here's my code so far:
angular.module('mobileDashboardApp')
.directive('httpErrorMessage', function (HTTPErrors) {
return {
template: '<div></div>',
link: function(scope, element, attrs) {
console.log("hello");
scope.$on(HTTPErrors.badRequest, function (event, args) {
// Inject template directly below 'element' <-- part I'm not sure how to do
});
}
};
});

Related

How to use directive-defined events to update my model

I am creating drag and drop functionality by creating a <dragItem> directive and a <droptTraget> directive, but I don't understand yet how to work with the inner and out scope in this way.
Here are my directives. The events triggers the functions properly, I just want the on dragstart event to store a value of the drag element and the drop event to trigger the function testAddSet() which adds the drag value to my model.
drag
angular.module('app.directives.dragItem', [])
.directive('dragItem', function(){
return { // this object is the directive
restrict: 'E',
scope: {
excercise: '='
},
templateUrl: "templates/dragTile.html",
link: function(scope, element, attrs){
element.on('dragstart', function (event) {
var dataVar = element.innerText;
// It's here that I want to send a dataVar to the $scope
});
}
};
});
drop
angular.module('app.directives.dropTarget', [])
.directive('dropTarget', function(){
return { // this object is the directive
restrict: 'E',
scope: {
day: '='
},
templateUrl: "templates/calDay.html",
link: function(scope, element, attrs){
element.on('drop', function (event) {
event.preventDefault();
// It's here that I'd like to take the value from the drag item and update my model
testAddSet() // doesn't work
$parent.testAddSet() // doesn't work
});
element.on('dragover', function (event) {
event.preventDefault();
});
}
};
});
Since you are using isolate scope, you need to define an attribute for the function binding.
angular.module('app.directives.dropTarget', [])
.directive('dropTarget', function(){
return { // this object is the directive
restrict: 'E',
scope: {
day: '=',
//Add binding here
testAddSet: '&'
},
templateUrl: "templates/calDay.html",
link: function(scope, element, attrs){
element.on('drop', function (event) {
event.preventDefault();
//Invoke the function here
scope.testAddSet({arg: value, $event: event});
});
element.on('dragover', function (event) {
event.preventDefault();
});
}
};
});
In your template, connect the function using the directive attribute.
<drop-target test-add-set="fn(arg, $event)" day="x"></drop-target>
For more information on isolate scope binding, see AngularJS $compile Service API Reference - scope.
I recommend that the event object be exposed as $event since that is customary with AngularJS event directives.
$event
Directives like ngClick and ngFocus expose a $event object within the scope of that expression. The object is an instance of a jQuery Event Object when jQuery is present or a similar jqLite object.
-- AngularJS Developer Guide -- $event
I think the easiest way to get your cross-directive communication is to make a scope variable on the host page and then pass it double-bound ('=') to both directives. That way, they both have access to it as it changes.

Directive link() querySelector

This it would be my directive
I try to add click events in the link function for my directive when it initiates, but it gives me empty element when I try to get the elements.
var link = function(scope, elem, attrs, controller){
console.log('WidgetId:' + controller.widget);
//Not working,
angular.element(elem[0].querySelectorAll('.widget-btn')).on('click', function(){
console.log('click event with querySelector');
});
// Directive element DOM
console.log(elem);
// That call return empty array, the PROBLEM is here
console.log(elem[0].querySelectorAll('.widget-btn'));
elem.on('click', function(e){
// But when I click in the directive, it returns the elements that I want
console.log(angular.element(elem[0].querySelectorAll('.widget-btn')));
});
scope.$on(scope.widget, function(){
console.log('directive get the controller message');
});
var widgetId = controller.widget;
function socketInit(){
socket.forward(widgetId, scope);
scope.$on('socket:'+ widgetId, function(){
console.log('Get socket msg');
});
};
socketInit();
}
return {
restrict: 'EA',
controller: controller,
// Our controller $scope will change for vm
controllerAs: 'vm',
// We set our widget info in the datasource.
scope: {
// After the configuration our datasource is accesible in the vm.datasource
datasource: '=',
addchanneluser: '&',
widget: '#'
},
bindToController: true,
templateUrl: '/angular-js/views/dashboard/directives/small/small.template.html',
link: link,
}
console.log(elem), it gives me directive element DOM so what I want to do is find in that DOM, all the elements that has channel class. I execute with querySelector and it gives me empty array.
But when all the directive its charge in the browser and I click in the directive console call is with content.
My questions is, it can be some initialisation problem or querySelector is charged after the link function.
Thanks

Define button click listener within isolate scope in angularjs

I want to create a directive as a component, such that its not dependent on any controllers as such.
I have been trying to find out how to get a button click listener defined. But couldnt suceed yet.
angular.module('nestedDirectives', [])
.directive("parent", function () {
function linker(scope, element, attribute, controllers) {
console.log("linker called");
element.on("click", function clicked(event) {
console.log("clicked");
console.dir(this);
element.prepend("<h1>Hello</h1>");
});
}
return {
restrict: 'A',
template: '<div><h5>An Item</h5><button ng-click="clicked()">Click Me</button></div>',
link: linker,
scope: {}
}
})
In the template, no matter what i click the element.on("click") would get called. I want to call a clicked() method when button is clicked.
Here is the Plunker for the same.
The link function gets the scope (an isolated scope in your case) as the first argument, so you can do something like:
.directive("parent", function () {
function linker(scope, element, attribute, controllers) {
console.log("linker called");
//add the "clicked" function to your scope so you can reference with ng-click="clicked" in your template
scope.clicked = function() {
console.log("clicked");
console.dir(this);
element.prepend("<h1>Hello</h1>");
};
}
return {
restrict: 'A',
template: '<div><h5>An Item</h5><button ng-click="clicked()">Click Me</button></div>',
link: linker,
scope: {}
};
});
Here is your updated plunkr http://plnkr.co/edit/7mlcSB4phPO5EdEQqTj0

Change child directive's attribute from a parent directive

I have a form directive that needs to communicate with a form-sections directive to tell it to change is layout. The change is triggered by a form-header directive.
<form>
<form-header></form-header>
<form-sections></form-sections>
</form>
I injected the form directive's controller in the form-header, so that the header can call the changeLayout function.
form directive:
compile: function(scope, element , attrs) {
element.find('form-sections').attr('current-view', 'tabs'); // initial layout
},
controller: function($scope, $element, $attrs) {
this.changeLayout = function(layout) {
$element.find('form-sections').attr('current-view', layout);
};
}
form-sections directive:
link: function (scope, element, attrs) {
attrs.$observe('currentView', function(currentView) {
console.log('observe:'currentView);
})
}
$observe is triggered only once, by the form directive's compile function, but not by it's controller. I tried it with an isolated scope in the form-section directive and use $watch, without any success..
Thanks as always!

How can I access a directive's ngModelController from another directive?

How can I access a directive's ngModelController from another directive?
The scenario
I'm creating a type ahead widget, which is composed of a typeAhead directive and autoCompletePopUp directive.
AutoCompletePopUp directive will interact with the typeAhead using typeAhead's controller.
But I don't know how to call typeAhead's $setViewValue from autoCompletePopUp when an item is selected.
Why not just add a function to the controller for typeAhead that calls $setViewValue on itself. In the context of typeAhead's controller you should have access to the scope. You can put the ngModelController for typeAhead on the scope if needed. Something like this:
angular.module("myModule").directive("typeAhead", function() {
return {
require: "ngModel",
controller: function($scope) {
this.setValue = function(value) {
$scope.ngModelController.$setViewValue(value);
};
},
link: function(scope, element, attributes, ngModelController) {
scope.ngModelController = ngModelController;
},
};
});
angular.module("myModule").directive("typeAhead", function() {
return {
require: "typeAhead",
link: function(scope, element, attributes, typeAheadController) {
scope.someAction = function(value) {
typeAheadController.setValue(value);
};
},
};
});
(protect against minification and move controllers into separate objects / files as desired; done inline here for convenience)

Resources