Access to method in the same .factory in Angular.js - javascript

I run the factory, and excecute the function "fn_generarPopupConfirm()" in any controller.
in this method, I have now created a template. This template has a buton that has an ng-click, which calls an existing function inside the same factory. In my example I have this:
<button type="submit" class="btn btn-primary" ng-click="fn_confirmar()">
How can I do it to call it ("oElim.fn_confirmar()")?, without needing to define a function in which I define a $scope object, to call the function needed. this function is present in the same factory.
controller: function($scope){
$scope.fn_confirmar=function(){
oElim.fn_confirmar();
}
},
I need the function to be called directly "oElim.fn_confirmar()" with the ng-click event. it's possible?
this is my factory.
.factory('eliminar', function($state,$rootScope,$uibModal,popup_generico) {
var oElim= {};
oElim.fn_generarPopupConfirm = function(objeto,array,titulo,contenido) {
$rootScope.modalInstances.push($uibModal.open({
template: '<form id="form_popup" class="form-horizontal"><div class="modal-header">
<h3 class="modal-title"><button type="submit" class="btn btn-primary"
ng-click="fn_confirmar()">
OK</button></div></form>',
controller: function($scope){
$scope.fn_confirmar=function(){
oElim.fn_confirmar();
}
},
backdrop: 'static'
}));
}
oElim.fn_confirmar = function(){
var index = oElim.array.indexOf(oElim.objeto);
oElim.array.splice(index, 1);
popup_generico.fn_CerrarModal();
}
return oElim;
})

I do not believe that this is possible within angular, as the template is a string that will be interpolated within the context of the controller, not the factory.
If you really want to have scope access to the oElim factory without injecting it into a controller, you could bind the oElim object directly to the $rootScope, giving you prototypal access to its methods within the template "$rootScope.oElim.fn_confirmar()" or equivalently just "oElim.fn_confirmar()" from any template you define in your angular app.

As I know it's not possible, but you can do the following:
controller: function($scope){
$scope.fn_confirmar = oElim.fn_confirmar;
},
or add the object to $rootScope
.factory('eliminar', function($state,$rootScope,$uibModal,popup_generico) {
var oElim= {};
$rootScope.oElim = oElim;
oElim.fn_generarPopupConfirm = function(objeto,array,titulo,contenido) {
$rootScope.modalInstances.push($uibModal.open({
template: '<form id="form_popup" class="form-horizontal"><div class="modal-header">
<h3 class="modal-title"><button type="submit" class="btn btn-primary"
ng-click="oElim.fn_confirmar()">
OK</button></div></form>',
controller: Function.prototype, //Just dummy function
backdrop: 'static'
}));
}
oElim.fn_confirmar = function(){
var index = oElim.array.indexOf(oElim.objeto);
oElim.array.splice(index, 1);
popup_generico.fn_CerrarModal();
}
return oElim;
})
or better, just used built-in angular event service
.factory('eliminar', function($state,$rootScope,$uibModal,popup_generico) {
var oElim= {};
oElim.fn_generarPopupConfirm = function(objeto,array,titulo,contenido) {
$rootScope.modalInstances.push($uibModal.open({
template: '<form id="form_popup" class="form-horizontal"><div class="modal-header">
<h3 class="modal-title"><button type="submit" class="btn btn-primary"
ng-click="$emit('fn_confirmar')">
OK</button></div></form>',
controller: Function.prototype, //Just dummy function
backdrop: 'static'
}));
}
oElim.fn_confirmar = function(){
var index = oElim.array.indexOf(oElim.objeto);
oElim.array.splice(index, 1);
popup_generico.fn_CerrarModal();
}
$rootScope.$on('fn_confirmar', oElim.fn_confirmar);
return oElim;
})

Related

Angularjs Manipulate each ng-repeat elements

I have a Custom directives that acts as a widget containing a list of buttons based on parameters passed in setting.
Setting passed in ng-repeat
$scope.btnGroup = [{"name":"toggle 1"},{"name":"toggle 2"}];
HTML
<div ng-controller="toggleButtonController" ng-init="init()" id="parent">
<div ng-repeat="btn in setting" style="display:inline">
<button class="btn btn-default" ng-bind="btn.name" ng-click="click()"></button>
</div>
So right now, my scenario is when i click one of the buttons, it will set the clicked button to btn-primary class and others to btn-default class and vice versa.
CONTROLLER
var app = angular.module('toggleButtonMod', [])
app.directive('toggleButton', function() {
return {
restrict: 'E',
scope: {
setting: '='
},
templateUrl: "app/Shared/togglebutton/toggleButtonView.html"
}
})
app.controller("toggleButtonController", function($scope) {
$scope.init = function() {
$scope.setupContent();
}
$scope.setupContent = function() {
}
$scope.click = function(event) {
console.log(event);
//here to change all the buttons in ng-repeat to btn-default class and the
//clicked button btn-primary class
}
})
Im stucked at the click function here..I have no idea how to manipulate each buttons in ng-repeat and modify their css class accordingly.
You can give the directive a controller and pass the directive's scope to the controller. With access to the scope, you can store a value that can be used in the template to conditionally add the class (using ngClass).
Directive:
.directive('toggleButton', function() {
return {
restrict: 'E',
scope: {
setting: '='
},
templateUrl: "app/Shared/togglebutton/toggleButtonView.html",
controller: function($scope){
$scope.toggleButton = {selected: null};
}
}
})
Template:
<div ng-repeat="btn in setting" style="display:inline">
<button class="btn" ng-class="{'btn-primary': btn === toggleButton.selected, 'btn-default': btn !== toggleButton.selected}" ng-bind="btn.name" ng-click="toggleButtonSelection(btn)"></button>
</div>
Note: Because ngRepeat creates a new scope for each item in the collection, in this case the value must be stored as an object property so that it is not shadowed in the item's scope and always references the directive's scope.
https://plnkr.co/edit/3xTpOFgpfYA99iKOi0rB?p=preview
in your html code add id attribute to button like as I have done in below code
<div ng-controller="toggleButtonController" ng-init="init()" id="parent">
<div ng-repeat="item in setting" style="display:inline">
<button class="btn btn-default" id= "item.name" ng-bind="item.name" ng-click="click($event)"></button>
</div>
$scope.click = function(event) {
var id = event.target.id;
var btn = document.getElementById(id);
if(btn.classList.contains('btn-default')){
btn.classList.remove('btn-default');
}
btn.classList.add('btn-primary');
angular.forEach(setting, function(value, key) {
var button = document.getElementById('value.name');
if(button.classList.contains('btn-primary')){
button.classList.remove('btn-primary');
}
button.classList.add('btn-default');
});
}

Angular-ui-bootstrap modal not showing data passed to it

I am trying to pass some model data into a modal window when it opens. Its in a $http.post success and also in failure then() with some different titles and button texts. I pass multiple data to it like:
//.then(){...//same as below }
,function (response){
$scope.PostRespData = response.data.message || 'Rq Failed';
$scope.pn = $scope.PostRespData.substring(53,63);
//(status=400) response modal string
$scope.name = 'Hey there!';
//modal options
$scope.opts = {
backdrop: true,
backdropClick: true,
dialogFade: false,
keyboard: true,
templateUrl : 'alreadyexists.html',
controller : ModalInstanceCtrl,
resolve: {}
};
$scope.opts.resolve.item = function() {
return angular.copy({name:$scope.name, errmsg:$scope.PostRespData, num:$scope.pn}); // pass name to modal dialo
}
//open the modal and create a modal Isntance
var modalInstance = $uibModal.open($scope.opts);
var ModalInstanceCtrl = function($scope, $uibModalInstance, $uibModal, item) {
$scope.item = item;
$scope.ok = function () {
$uibModalInstance.close();
};
$scope.cancel = function () {
$uibModalInstance.close();
}
My HTML template looks like
<div class="modal-header">
<h1>{{item.name}}</h1>
</div>
<div ng-controller="Nav" class="modal-body">
<p>{{item.errmsg}}
View {{item.num}}
</p>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="ok()">Edit Current Details</button>
<button class="btn btn-warning" ng-click="cancel()">Edit {{item.num}}</button>
</div>
I get my modal and I also get the static data but data being passed to it does not reflect. I've spent the whole day trying to make this work.
Edit: Adding current output pic.
Please help me!
As pointed out by #charlietfl, it was a hoisting issue. To use the above code, move var ModalInstanceCtrl = func.. outside the button's ng-click call of $http.

Why is my angular binding read only in a bootstrap UI modal in an MVC5 project?

I am trying to pop up a modal to get some input, but the angular binding via ng-model seems to be read only. This is my modal markup:
<script type="text/ng-template" id="signatureWindow.html">
<div class="modal-header">
<h4 class="modal-title" id="myModalLabel">Signature Capture</h4>
</div>
<input type="text" width="100px" ng-model="theName" />
<div class="modal-footer">
<button ng-click="accept()" class="btn btn-primary">Accept</button>
<button ng-click="cancel()" class="btn btn-default">Cancel</button>
</div>
</script>
Then, I invoke this modal as follows:
$scope.getSignatureModal = function(signatureBase64) {
var modalInstance = $modal.open({
templateUrl: 'signatureWindow.html',
controller: 'SignatureModalController',
size: 'lg',
resolve: {
signatureData: function() {
return signatureBase64;
}
}
});
modalInstance.result.then(function(signatureData) {
alert('Signed');
signatureBase64 = signatureData;
}, function() {
alert('Canceled');
});
};
And the following controller code for the modal:
MlamAngularApp.controller('SignatureModalController', function($scope, $modalInstance, signatureData) {
$scope.base64 = signatureData;
$scope.thename = "NamesRus";
$scope.accept = function() {
debugger;
$modalInstance.close($scope.thename);
}
$scope.cancel = function() {
$modalInstance.dismiss('cancel');
}
});
The modal pops up as expected, and the input has the initial value "NamesRus", but when I close the modal, invoking accept in the modal controller, $scope.thename still has it's initial value, not any new value I type when the modal is active. What could be wrong here?
NOTE: At the debugger breakpoint in accept, no matter what I type in the modal's input, theName still has the initial assigned value.
MORE: My Plunker for this works fine. It's when in-place, in an ASP.NET MVC5 project, that I get the strange behaviour.
I think that you mix up two differents scopes.
If you want several variables to be passed to and retrieved from the modal you have to mention them:
in the resolve attribute
resolve: {modalData: function (){return {signatureData:$scope.base64,name:$scope.theName}}}
pass modalData as dependencie to your controller
MlamAngularApp.controller('SignatureModalController', function($scope, $modalInstance, modalData)
update the modal controller $scope with modalData
$scope.signatureData = modalData.signatureData;
$scope.name=modalData.name;
invoke
$modalInstance.close({signatureData:$scope.base64,name:$scope.theName})
reassign the original $scope with the result of promise
modalInstance.result.then(function (data) {
$scope.base64 = data.signatureData;
$scope.thename=data.name;
}
take a look at this plunker forked from ui-boostrap modal orginal example: http://plnkr.co/edit/whLSYt?p=info

Controller is not defined

I'm trying to use the Angularjs-UI Modal into my application and I'm a little confused as to what goes where. I have a button for new groups which calls a model, the models controller is in another file. I'm trying to call the newGroupCtrl within the groupCtrl but it's returning undefined.
HTML for new group button:
<button type="button" class="delGroupBtn" ng-click="newGroup()">New Group</button>
In my groupCtrl I have this newgroup() function:
$scope.newGroup = function (){
var modalForm = '/Style%20Library/projects/spDash/app/partials/newGroup.html';
var modalInstance = $modal.open({
templateUrl: modalForm,
backdrop: true,
windowClass: 'modal',
controller: newGroupCtrl,
resolve:{
newGroup:function (){
return $scope.newGroup;
}
}
});
};
Then I've got my newGroup.html (the modal) which is where the user would enter the groups name, description, owner:
<div class="modal-header">
<form>
<label for="groupName">Group Name:
<input id="groupName" type="text" ng-model='newGroup.name'>
</label>
<hr>
<label for="groupDesc">Group Description:
<input id="groupDesc" type="text" ng-model='newGroup.desc'>
</label>
<hr>
<label for="groupOwner">Group Name:
<select id="groupOwner" type="text" ng-model=''></select>
</label>
<div class="modal-footer">
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
<button class="btn primary-btn" type="button" ng-click="newGroup()">Create</button>
</div>
</form>
</div>
Here's the newGroupCtrl:
spApp.controller('newGroupCtrl',
function newGroupCtrl($scope, $modalInstance){
$scope.newGroup = {
name:null,
desc:null
};
$scope.submit = function(){
console.log('creating new group');
console.log(newGroup);
$modalInstance.dismiss('cancel');
}
$scope.cancel = function (){
$modalInstance.dismiss('cancel');
};
$modalInstance.result.then(function (){
groupService.newGroup($scope.newGroup);
}, function (){
console.log('No new group created.');
});
}
);
I've injected the group and newGroup controllers with my group service which is where I'm trying to get the information from the model to the groupService function to make the AJAX call to my server and create the new group. It seems like I'm repeating myself in both controllers with the $model.open({})
Here's a plunker
When controller is defined as part of the angular module (using .controller() method) than it must be referenced as a string.
When controller is defined as a simple JS function, then it must be referenced through a variable.
In you modal configuration object, you referenced newGroupCtrl as a variable, not as a string.
...
controller: newGroupCtrl,
...
vs
...
controller: 'newGroupCtrl',
...
But your controller is defined with angular.module().controller():
spApp.controller('newGroupCtrl',
function newGroupCtrl($scope, $modalInstance){...})
To fix, you need to put the name of the controller in quotes OR define the controller as a simple standalone JS function.
So, it's either this:
...
controller: 'newGroupCtrl',
...
spApp.controller('newGroupCtrl',
function newGroupCtrl($scope, $modalInstance){...})
OR this:
...
controller: newGroupCtrl,
...
function newGroupCtrl($scope, $modalInstance){...}

Instantiate and initialize controller in AngularJS

I have a problem instanciating controller with Angular. I have a main controller AlkeTypeDefListController from which I want to dynamically create/remove controllers of type AlkeTypeDefController, so I have done that :
Code of AlkeTypeDefListController:
// Create main controller
Alke.controller('AlkeTypeDefListController', ['$scope', '$controller', function($scope, $controller)
{
var primitives =
[
];
// Add some properties to the scope
angular.extend($scope,
{
typedefs : primitives,
addTypeDef : function()
{
var controller = $controller("AlkeTypeDefController", {$scope:$scope.$new()});
$scope.typedefs.push(controller);
}
});
}]);
Code of AlkeTypeDefController:
// Create main controller
Alke.controller('AlkeTypeDefController', ['$scope', '$controller', function($scope, $controller)
{
// Add some properties to the scope
angular.extend($scope,
{
name : "New Type",
fields : [],
addField : function()
{
}
});
}]);
The html code is this one:
<div id="typedefs-editor" ng:controller="AlkeTypeDefListController">
<button ng:click="addTypeDef()">Add</button>
<button>Remove</button>
<div id="typedef-list">
<ul class="list">
<li ng:repeat="typedef in typedefs">{{typedef.name}}</li>
</ul>
</div>
</div>
The problem does not really come from the instantiation (which works fine), but from the initialization. In fact, when the new "li" appears when I push the "Add" button, the text "New type" (initialized in the controller) does not appear.
I think it is about the scope or something like that, but I can't really find how to fix this.
I wanted to know if this method seems correct, and also how could I fix the problem I have.
Thanks
Reading the code, I understand that you want to create typedefs dynamically and those typedef items have to be controlled by an AlkeTypeDefController.
In that case I would create AlkeTypeDefController using ng:controller directive, so you don't need to create the controller programmatically, because then you would need to attached it to the view and that's just what the ngController directive does for you.
Notice AlkeTypeDefListController does not create a AlkeTypeDefController controller, this is done in the view
Demo on Plunker
Controllers:
.controller('AlkeTypeDefListController', ['$scope', function($scope) {
var primitives = [];
$scope.typedefs = primitives;
$scope.addTypeDef = function() {
var typeDef = { name: 'New Type' };
$scope.typedefs.push(typeDef);
}
}])
.controller('AlkeTypeDefController', ['$scope', function($scope) {
$scope.addField = function() {
alert('add Field');
}
}]);
View (notice how ng-controller directive is specified in li element):
<div id="typedefs-editor" ng:controller="AlkeTypeDefListController">
<button ng:click="addTypeDef()">Add</button>
<button>Remove</button>
<div id="typedef-list">
<ul class="list">
<li ng:repeat="typedef in typedefs" ng:controller="AlkeTypeDefController">
{{typedef.name}}
</li>
</ul>
</div>
In the code above, ngRepeat is going to create a new $scope for each typedef. AlkeTypeDefController then decorates that scope with functions and values.
I hope it helps
When you call $controller("AlkeTypeDefController") it will essentially call new on the AlkeTypeDefController constructor and give you back the return value not the scope. You are assign the name attrubute to the scope though so it is not being accessed in your html when you have typedef.name.
Try changing your AlkeTypeDefController to this:
Alke.controller('AlkeTypeDefController', function() {
this.name = "New Type";
this.fields = [];
this.addField = function() {};
});
Then you can instantiate it with: var controller = $controller("AlkeTypeDefController"); and you shouldn't need to worry about creating nested scopes.
If I get what you're saying correctly then I think I'd try to leverage the power of a custom directive here instead of dynamically generating controllers.
plunker
Controller:
Alke.controller('alkeTypeDefListController', ['$scope', '$controller',
function($scope, $controller) {
var primitives = [];
var addTypeDef = function() {
$scope.typedefs.push({
name: 'new name'
});
};
var removeTypeDef = function(){
$scope.typedefs.pop();
};
var properties = {
typedefs: primitives,
addTypeDef: addTypeDef,
removeTypeDef: removeTypeDef
};
// Add some properties to the scope
angular.extend($scope, properties);
}
]);
Directive:
Alke.directive('alkeTypeDef', function() {
return {
restrict: 'A',
scope: {
typeDef: '=alkeTypeDef'
},
template: '{{typeDef.name}}',
link: function(scope, element, attr) {
var properties = {
fields: [],
addField: function() {
}
};
angular.extend(scope, properties);
}
};
});
HTML:
<div ng-app='Alke'>
<div id="typedefs-editor" ng-controller="alkeTypeDefListController">
<button ng-click="addTypeDef()">Add</button>
<button ng-click="removeTypeDef()">Remove</button>
<div id="typedef-list">
<ul class="list">
<li alke-type-def='typedef' ng-repeat="typedef in typedefs"></li>
</ul>
</div>
</div>
</div>
If you want a controller then you can use one in the directive instead of a linking function.

Categories

Resources