Same directive with different message - angularJS - javascript

I have buttons like submit, reject and cancel. If i click on this button a small div with comment shows up and a ok and cancel button will be shown. On click of ok popup with 'are you sure' message popups up.
<button type="button" ng-click="showDiv = !showDiv">Submit
</button>
<button type="button" ng-click="showDiv = !showDiv">Reject
</button>
I am using a popup modal directive like this for the small div as i mentioned above:
<div ng-show="showDiv">
<yes-no msg="are you sure"></yes-no>
</div>
Now I want to change the msg on click of each button. Suppose if i click 'Submit' my msg should be 'are you sure to submit' if i click 'reject' my msg should be 'are you sure to reject'.
directive:
mainapp.directive('yesNo', function($modal){
return {
restrict: 'A',
scope: {
msg: '#msg'
},
link: linkFn
};
function linkFn(scope, element, attrs) {
var msg = attrs.msg;
var modalTemplate = '<div class="modal-content">' +
' <div class="modal-body">' +
' <h4 class="modal-title">' + msg + '</h4>' +
' </div>';
var modalInstance = $modal.open({
template: modalTemplate,
controller: 'yesNoModalCtrl'
});
});
}
});
How to achieve this? I will not be able to post the code here.

<input type="button" name="submit" ng-click="buttonclick('are you sure to submit')"/>
<input type="button" name="reject" ng-click="buttonclick('are you sure to reject')"/>
<div ng-show="showDiv">
<yes-no msg={{message}}></yes-no>
</div>
In you main controller:
app.controller("mainController", function($scope){
$scope.message="";
$scope.buttonclick = function(msg){
$scope.message= msg;
}
});
app.directive("yesNo", function(){
return{
restrict: 'E',
scope:{
msg:'#'
},
link: linkFn,
controller: 'yesNoModalCtrl'
}
});
In directives Link function
function linkFn(scope, element, attrs) {
attrs.$observe('msg', function(msg) {
// this function gets triggered each time "msg" is changed
// You can do whatever you want here
if (msg) {
var modalTemplate = '<div class="modal-content">' +
' <div class="modal-body">' +
' <h4 class="modal-title">' + msg + '</h4>' +
' </div>';
var modalInstance = $modal.open({
template: modalTemplate,
controller: 'yesNoModalCtrl'
});
}
});
}
plunker

Create a controller function:
$scope.showModal = function(msg) {
$scope.showDiv = !$scope.showDiv;
$scope.msg = msg;
}
And in your buttons:
<button type="button" ng-click="showModal('Are you sure')">Submit
</button>
<button type="button" ng-click="showModal('Some other text')">Reject
</button>
<div ng-show="showDiv">
<yes-no msg="msg"></yes-no>
</div>

Related

ng-click in directive not calling function defined in controller scope

Everything seems to render properly but my ng-click="check($event)" is not firing when I click on one of the four buttons. I even added an alert to the check($event) function but it's not coming up. Heres the codepen http://codepen.io/theMugician/pen/MKOzzV?editors=101
simonApp.directive('pads', ['lightIt', 'soundIt', function(lightIt,soundIt) {
var template = '';
template += '<button ng-click="check($event)" id=' + '{{index}} ' + 'class="pad pad-' + '{{color}}' + '">';
template += '<div class="ripple js-ripple">';
template += '<span class="ripple-circle ' + 'ripple-' + '{{color}}' + '"></span></div>';
template += '</button>';
return {
restrict: 'E',
replace: true,
scope: {
color: '#color',
index: '#index'
},
link: function(scope, element, attrs) {
scope.createRipple = function(e){
lightIt.createRipple(e, this);
}
//scope.$emit('index', scope.index);
/*
var index = parseInt(scope.index);
scope.playSound = function() {
soundIt(1);
}*/
console.log("scope.index: " + scope.index);
//console.log("scope.playSound: " + scope.playSound);
element.on('click', scope.createRipple);
//element.on('animationend', scope.endRipple);
},
template: template
};
}]);
Here is the check() function in the controller
$scope.check = function(e) {
alert("check works");
var id = e.currentTarget.id;
if($scope.init){
if(sequence[turn] === id){
turn++;
if(turn === sequence.length){
$scope.step++;
setTimeout(function(){
newRound();
}, 1000);
}
}else{
if($scope.isStrict){
setTimeout(function(){
alert('game over');
$scope.reset();
}, 300);
}else{
$scope.displaySeq(sequence);
}
}
}
}
You cannot call controller method from directive like that.
In case you need scope isolation you have to use expression binding ( '&' scope parameters) or turn off scope isolation all together ( remove scope key from directive definition )
See excellent video from John Lindquist for example of using scope expression binding.
var app = angular.module('app', [])
app.directive("pads", function() {
return {
restrict: "E",
scope: {
check: "&"
},
template: '<div class="button" ng-click="check({message: value})">click</div></div>',
link: function(scope) {
scope.value = 'message to controller'
}
};
});
app.controller('myCtrl', function() {
this.doCheck = function(message) {
alert(message) // alerts "message to controller"
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='myCtrl as ctrl'>
<pads check="ctrl.doCheck(message)"></pads>
</div>

scope variable isn't reflected in directive

I'm trying to fill the body attribute, so my module will print it as it's body part, yet I have no idea why it's not working, even I tried $scope.$apply() in several places.
var app = angular.module('ClientLogger', ['ngRoute'])
app.controller('global', function($scope, $compile) {
$scope.window = window
$scope.sampletext = "sampleText";
$scope.showModal = false;
$scope.toggleModal = function(text) {
$scope.text = text;
$scope.showModal = !$scope.showModal;
};
});
app.directive('modal', function() {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude> {{ body }} </div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace: true,
scope: true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.body = attrs.body;
scope.$watch(attrs.visible, function(value) {
if (value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
});
});
}
};
});
<body ng-app='ClientLogger' ng-controller='global'>
<a class="btn btn-default" ng-click="toggleModal(sampletext)"> sample </a>
<modal title="Message Details" body="{{text}}" visible="showModal"></modal>
</body>
As you can see, after i click the link, it will change the variable $scope.text and it will reflect to the modal. But I can't manage to do it. Since I#m very new about this Angular, I still have troubles about understanding its mechanics, so any specific details will be really good for me.
Any recommendations?
When you retrieve your attrs.body, you are retrieving undefined data.
You can use a Factory to share your data. You have to know that all angular services are singletons, so there is only one instance of a given service.
Thanks to this, you can easily share your data between your controller and your directive.
So when you will trigger an action in your Controller, you will set your data into your factory, then you can retrieve your data into your directive.
Controller
(function(){
function Controller($scope, Service) {
$scope.myText = 'sample';
$scope.showModal = false;
$scope.toggleModal = function() {
//Set the myText value by using our Service.set() method
Service.set($scope.myText);
$scope.showModal = !$scope.showModal;
};
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
Service
(function(){
function Service(){
var data;
function set(value){
data = value;
}
function get(){
return data;
}
return {
get: get,
set: set
};
}
angular
.module('app')
.factory('Service', Service);
})();
Directive
(function(){
function modal(Service) {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body"> {{ body }} </div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace: true,
scope: true,
link: function (scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value) {
value
//Retrieve your data by using Service.get() method, and show our modal
? ( scope.body = Service.get(), $(element).modal('show') )
: $(element).modal('hide')
});
$(element).on('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
});
});
}
};
}
angular
.module('app')
.directive('modal', modal);
})();
Then, you can call your directive into your HTML.
HTML
<body ng-app='app' ng-controller="ctrl">
<input type="text" ng-model="myText">
<a class="btn btn-default" ng-click="toggleModal()"> sample </a>
<modal title="Message Details" visible="showModal"></modal>
</body>
You can see the Working Plunker

Single edit hyperlink option for all the field edits

I have created an application in AngularJS with edit, save and cancel options, the application is working fine, right now i am having edit option for all the three fields, but how can i have a single edit option for making all the fields editable and save and cancel similarly
Can anyone please tell me some solution for this
DEMO
HTML
<div ng-controller="LocationFormCtrl">
<h2>Editors</h2>
<span ng-repeat="location in locations">
<div class="field">
<strong>State:</strong>
<div click-to-edit="location.state"><input ng-model="location.state"/></div>
</div>
<div class="field">
<strong>City:</strong>
<div click-to-edit="location.city">
<select ng-model="location.city" ng-options="loc.city as loc.city for loc in selectableCities"></select>
</div>
</div>
<div class="field">
<strong>Neighbourhood:</strong>
<div click-to-edit="location.neighbourhood"><input ng-model="location.neighbourhood"/></div>
</div>
<hr></hr>
</span>
</div>
I created a new directive that uses you directive. Also i updated your directive a bit.
Not sure if you wanted this.
you can find the jsFiddle demo here.
updated your directive so that it does not show individual save n cancel when in edit all mode.
you can find the updated jsFiddle demo here.
app.directive("clickToEditAll",function(){
var partial = '<div><div class="field">' +
'<strong>State:</strong>' +
'<div click-to-edit="myData.state" external-controle="externalControle"><input ng-model="myData.state"/></div>' +
' </div>' +
'<div class="field">' +
'<strong>City:</strong>' +
'<div click-to-edit="myData.city" external-controle="externalControle">' +
'<select ng-model="myData.city" ng-options="loc.city as loc.city for loc in selectableCities"></select>' +
'</div>' +
'</div>' +
'<div class="field">' +
'<strong>Neighbourhood:</strong>' +
'<div click-to-edit="myData.neighbourhood" external-controle="externalControle"><input ng-model="myData.neighbourhood"/></div>' +
'</div>' +
'<button ng-show="externalControle.editAll !== true" ng-click="editAllClicked()">Edit All</button><button ng-show="externalControle.editAll === true" ng-click="saveAllClicked()">Save</button><button ng-show="externalControle.editAll === true" ng-click="cancelAllClicked()">Cancel</button><hr/></div>'
var retValue = {
restrict: "A",
template:partial,
scope:{
myData:"=",
selectableCities:"=",
externalControle: "="
},
link:function(scope, elements, attributes){
scope.editAllClicked = function(){
scope.externalControle.editAll = true;
}
scope.saveAllClicked = function(){
scope.externalControle.saveAll = true;
}
scope.cancelAllClicked = function(){
scope.externalControle.cancelAll = true;
}
}
}
return retValue;
});

angular dialog can't be shown after clicking element

I try to make my own button using directive.
The dialog (bootstrap.dialog) should be hired after clicking the button.
But, it won't.
Tried without click event, it works.
Using this:
- AngularJS v1.0.8
- Bootstrap 2.3.2
- Angular-bootstrap 0.3.0
here's my directive...
.directive("ucayButton", function($dialog) {
return {
restrict: 'EA',
template: '<button ng-transclude></button>',
replace: true,
transclude: true,
link: function(scope, element, attrs) {
element.addClass('btn btn-primary');
var t = '<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" ng-click="close()" aria-hidden="true">×</button>' +
'<h4 class="modal-title">Modal title</h4>' +
'</div>' +
'<div class="modal-body">' +
'<p>One fine body…</p>' +
'</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-default" ng-click="close()">Close</button>' +
'<button type="button" class="btn btn-primary" ng-click="close()">Save changes</button>' +
'</div>' +
'</div><!-- /.modal-content -->' +
'</div><!-- /.modal-dialog -->';
var modalOpts = {
backdrop: true,
keyboard: true,
backdropClick: true,
template: t,
controller: 'dialogCtrl'
};
scope.openDialog = function(){
console.log('confirmation called'); //always shown when function was called
var d = $dialog.dialog(modalOpts);
d.open().then(function(result){
if(result)
{
alert('dialog closed with result: ' + result);
}
});
};
angular.forEach(element, function(el) {
el.addEventListener('click', function() {
scope.openDialog(); // the function was hired, but the dialog didn't
});
});
scope.openDialog(); //hired
}
};
})
addEventListener is not an angular function, so when you perform code that affects $scope variables you need to get those changes back into the digest cycle.
Try this instead:
el.addEventListener('click', function() {
if(scope.$$phase) {
scope.openDialog();
} else {
scope.$apply(function() {
scope.openDialog();
});
}
});
This checks the $$phase of the scope, which is truthy if you are running code from within a digest cycle. If you are already in a digest cycle then there is no need to wrap the code with an $apply call. If you are not then wrapping the code in an $apply call lets angular know that it needs to digest the changes you are making.

Is there any way to just use a child directive as a placeholder for holding content?

I am new to angularjs. Want to see if there is any way to just use a child directive as a placeholder for holding content but for really rendering?
I don't want to do rendering in the child directive because I want to let the parent to do everything. So I can have some other special logic in the parent directive.
angular.module('components', []).
directive('tabs', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
controller: function($scope, $element) {
var panes = $scope.panes = [];
$scope.select = function(pane) {
angular.forEach(panes, function(pane) {
pane.selected = false;
});
pane.selected = true;
}
$scope.createPane = function() {
var pane = panes[panes.length - 1];
var clonedPane = Angular.copy(pane);
panes.push(clonedPane);
}
this.addPane = function(pane) {
if (panes.length == 0) $scope.select(pane);
panes.push(pane);
}
},
template: '<div class="tabbable tabs-left">' +
'<ul class="nav nav-tabs">' +
'<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">' +
'{{pane.title}}' +
'</li>' +
'<li ng-class="addLink"><a ng-click="createPane()"><i class="icon-plus"></i> tab</a></li>' +
'</ul>' +
'<div class="tab-content">' +
'<div ng-repeat="pane in panes" class="tab-pane" ng-class="{active: selected},{{pane.pclass}}" id="{{pane.id}}">' +
'{{ pane.content }}' +
'</div>' +
'</div>' +
'</div>',
replace: true
};
}).
directive('pane', function() {
return {
require: '^tabs',
restrict: 'E',
scope: {
title: 'bind',
pclass: 'bind',
id: 'bind'
},
link: function(scope, element, attrs, tabsCtrl) {
var text = element.text();
tabsCtrl.addPane({
title: scope.title,
pclass: scope.pclass,
id: scope.id,
content: text
});
}
};
})
Corresponding html code:
<tabs>
<pane title="tab 1" id="tab1" pclass="tab">
hello
</pane>
<pane title="tab 2" id="tab2" pclass="tab">
world
</pane>
</tabs>
I tried something like the above but nothing is pushed into panes. Seems like the link function of the child directive (pane) is never called. So as a result, only the link for adding tab is displayed.
Any ideas?
The easiest (though sort of annoying) way to approach this would be to have a template for each pane.
In html:
<tabs>
<pane title="tab 1" id="tab1" pclass="tab" template="pane1-templ">
</pane>
<pane title="tab 2" id="tab2" pclass="tab" template="pane2-templ">
</pane>
</tabs>
<script type="text/ng-template" src="pane1-template">hello</script>
<script type="text/ng-template" src="pane2-template>wolrd</script>
In your directive:
'<div class="tab-content">' +
'<div ng-repeat="pane in panes" class="tab-pane" ng-class="{active: selected},{{pane.pclass}}" id="{{pane.id}}">' +
'<div ng-include src="pane.template"></div>' +
'</div>' +
'</div>'
Or.. have you tried doing this to fix it?
In pane:
var html = elm.html();
//...
pane.html = html;
In tabs:
<div ng-bind-html-unsafe="pane.html"></div>
Perhaps the reason why it is not working is because in your child directive you have no template. Without a template, the directive does not know where and how to render the directive.
What you could do is have something like:
template : '<div style="display:none;" ng-transclude></div>'
in your child template..
and your element.text() should still work!
Without a template the linking function would never get the element so your child directive will fail right there.
With the template above it should work.

Categories

Resources