Ionic + Angular ng-click not bind function from dynamic html element - angularjs

I have an ion-list and I create each ion-item from a select statment. The ion-item tag has a ng-click event that call a modal window but it never call the show() method from controller. For test I put a static ion-item without DOM modification and it works well.
This is the code:
Modal controller
function uib_w_27_modal_controller($scope, $ionicModal) {
$scope.modal = $ionicModal.fromTemplate($(".uib_w_27").html(), {
scope: $scope,
animation: 'slide-in-up'
});
$scope.show = function() {
$scope.modal.show();
};
$scope.close = function() {
$scope.modal.hide();
};
//Cleanup the modal when we're done with it!
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
});
};
Dynamic element
function getFarmaciasSelect(tx, result){
var elem = '';
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
elem += '<ion-item class="item widget uib_w_24 d-margins item-avatar item-icon-right" data-uib="ionic/list_item_avatar" data-ver="0">' +
'<img src="images/Strabburg.jpg">' +
'<h2>' + row['nombre'] + '</h2>' +
'<p>' + row['calle'] + ' ' + row['altura'] + '</p>' +
'<a href="tel:' + row['fijo'] + '"style="text-decoration:none;color:#4CAF50" >' + row['fijo'] + '</a>' +
'<i class="icon ion-plus-circled ion" uib-icon-position="right" ng-controller="uib_w_27_modal_controller" ng-click="show()" data-email="email#email.com"></i>' +
'</ion-item>';
console.log(elem);
}
$('#farmacias-list').html(elem);
}
Thanks for help!

If you really need to keep generating in your code then you need compile your content before add to '#farmacias-list'
$('#farmacias-list').html($compile(elem)($scope));
but even it work, I will recommend you to use collection-repeat to generate content in angular context.

Related

UibModal not passing angular.noop or undefined in function bindings when opening modal

Okay so I am using angularjs 1.5.8 and uibmodal to open a modal with a component inside the modal. I want to have the components be able to have some default functionality but also be able to override it from the consuming context so i'm trying to check if the consuming context has set that binding variable 'submit'. This works just fine when I add the component to my html and define the function in the consuming controller,
<contacts-form submit="vm.consumingContextSubmit(form, model)"></contacts-form>
but I'm not able to determine if the function binding 'submit' is set when I open the form via uibmodal.
If I'm going about this the wrong way feel free to suggest a better pattern.
I have the bindings for the component defined to allow undefined: (have tried with the regular old '&' as well.)
angular.
module(APPNAME).
component('contactsForm', { // This name is what AngularJS uses to match to the `<contacts-form>` element.
templateUrl: '../Scripts/components/add-update-forms/contacts-form/contacts-form.component.html',
controller: 'ContactsFormController',
controllerAs: 'cfc',
bindings: {
modelId: '=',
submit: '&?',
cancel: '&?'
}
});
Here is the call in the consuming context:
vm.$modalService.openFormModal('contacts', contactId, titleText, function(form, model) {
console.log(form);
console.log(model);
});
Here is the service function opening the modal via uibModal
function openFormModal(modelName, dataModelId, titleText, submitFunction) {
// convert undefineds to blank strings
titleText = titleText == undefined ? '' : titleText;
dataModelId = dataModelId == undefined ? '' : dataModelId;
var templateString = '<div class="inmodal"><div class="modal-header"><h4 class="modal-title">'
+ titleText
+ '<button class="pull-right btn btn-danger" ng-click="$close()">X</button></h4></div>'
+ '<div class="modal-body" style="overflow:auto;background-color: white !important;padding:0px;">'
+ '<' + modelName + '-form model-id="\'' + dataModelId + '\'" submit="uib.submitFunction(form, model)" cancel="$close()"></' + modelName + '-form></div></div>';
$uibModal.open({
animation: true,
template: templateString,
controller: ['$scope', 'submitFunctionParam', function ($scope, submitFunctionParam) {
var vm = this;
vm.$scope = $scope;
// all this should be unneed.
// it should be the same as vm.submitFunction = submitFunctionParam
if (submitFunctionParam !== undefined) {
vm.submitFunction = submitFunctionParam;
} else { // unneeded but to be explicit
vm.submitFunction = undefined;
}
}],
controllerAs: 'uib',
resolve: {
submitFunctionParam: function () {
return submitFunction;
}
}
})
But then when i'm inside my contacts form component:
function _submit() {
console.log(vm.submit);
if (vm.submit === angular.noop || vm.submit === undefined) {
validate(vm.form);
if (vm.form.$valid) {
//do default updates
var contact = vm.dataModel;
if (vm.contactUrlId) {
vm.$contactsService.updateContact(contact).then(_onUpdateContactSuccess);
} else {
vm.$contactsService.createContact(contact).then(_onCreateNewContactSuccess);
}
} else {
vm.$alertService.warning('Form is invalid. Please fix errors.');
}
} else {
//call function from consuming context
vm.submit({ form : vm.form }, { model : vm.dataModel });
}
};
In my components I have a submit function defined that checks for angular.noop or undefined but i keep getting this function:
ƒ (locals) {
return parentGet(scope, locals);
}
Okay I'm not sure exactly the mechanics so feel free to explain it and i'll mark it as the answer but just adding logic to where i build the template worked and passed in undefined as expected.
var templateString = '<div class="inmodal"><div class="modal-header"><h4 class="modal-title">'
+ titleText
+ '<button class="pull-right btn btn-danger" ng-click="$close()">X</button></h4></div>'
+ '<div class="modal-body" style="overflow:auto;background-color: white !important;padding:0px;">'
+ '<' + modelName + '-form model-id="\'' + dataModelId + '\'" ';
if (submitFunction === angular.noop || submitFunction === undefined) {
} else {
templateString = templateString + 'submit = "uib.submitFunction(form, model)" ';
}
templateString = templateString + 'cancel = "$close()" ></' + modelName + ' - form ></div ></div > ';

How to trigger mailto in AngularJS controller without changing window location

I have an angular controller that triggers a "mailto" link when a mail icon is clicked
angular
.module('app')
.component('header', {
template: '<i class="fa fa-envelope" aria-hidden="true"></i>',
controller: HeaderController,
controllerAs: 'headerCtrl'
});
function HeaderController() {
var vm = this;
vm.sendMail = sendMail;
function sendMail(response) {
var email = 'test#mail.com';
var subject = 'email%20subject';
var body = 'email%20body';
vm.mailToUri = 'mailto:' + email + '?subject=' + subject + '&body=' + body;
$window.location = vm.mailToUri;
}
}
Unfortunately, this is running in the same application as a directive that calls a logout url when the browser is closed
angular
.module('app')
.directive('onCloseLogout', onCloseLogout);
function onCloseLogout($http, $window) {
return {
restrict: 'AE',
link: function () {
$window.onbeforeunload = function () {
$http.get('/logout');
};
}
};
}
So, when the email link is clicked, the onCloseLogout directive is triggered, and the user is logged out.
Is there another way to open an email in angular, or to send a get request to the logout URL on browser close?
Turns out I had over engineered the solution. I added the mailToUri to the anchor tag as the ng-href attribute and it all works fine now
angular
.module('app')
.component('header', {
template: '<a ng-href="{{headerCtrl.mailToUri}}"><i class="fa fa-envelope" aria-hidden="true"></i></a>',
controller: HeaderController,
controllerAs: 'headerCtrl'
});
function HeaderController() {
var vm = this;
var email = 'test#mail.com';
var subject = 'email%20subject';
var body = 'email%20body';
vm.mailToUri = 'mailto:' + email + '?subject=' + subject + '&body=' + body;
}

Not able to update angular ui modal values back to the caller screen

I'm trying to invoke angularUI modal when I click on an element of a list. I can successfully load the modal, change the value in the modal, and come back to the caller screen. But I don't know how to update the list on caller screen. I tried various things like updating inside init() method of the controller of caller screen but that doesn't get called on modal close. I tried to assign as variable inside controller but that doesn't work either. My guess is that something needs to be done inside below method.
modalInstance.result.then(function(personModified) {
$log.info('personModified = ' + personModified.name + ' Finished at: ' + new Date());
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
Tried looping through like below:
modalInstance.result.then(function(personModified) {
for (int i = 0; i < modalCtrl.people.length; i++) {
if (modalCtrl.people[i]._id === personModified._id) {
modalCtrl.people[i] = personModified;
}
}
$log.info('personModified = ' + personModified.name + ' Finished at: ' + new Date());
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
But modalCtrl is not recognized inside modalInstance.result.then(function(){}) method. I don't know what else can I do to update my list on caller screen. Any help would be hugely appreciated. Here is the plunker http://plnkr.co/edit/DR6Gadoh3rXegCrTOTzB?p=preview
Pass array element index along with the current element while opening modal like modalCtrl.open('lg', person, $index), when success call of modal we can update this.people array of that specific index.
HTML
<div ng-repeat="person in modalCtrl.people">
<a ng-click="modalCtrl.open('lg', person, $index)" class="undecorated-link">
<p class="text-center">{{person.name}}</p>
</a>
</div>
CODE
modalCtrl.open = function(size, selectedPerson, index) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
scope: $scope,
resolve: {
person: function() {
return angular.copy(selectedPerson);
}
}
});
modalInstance.result.then(function(personModified) {
$log.info('personModified = ' + personModified.name + ' Finished at: ' + new Date());
modalCtrl.people[index] = personModified;
}, function() {
$log.info('Modal dismissed at: ' + new Date());
});
};
Working Plunkr
Hope this could help you, Thanks.

How to add and remove div with posts between table rows angularjs ?

I have a table with staff are represented as a table. I would like by click on item show list with comments for current employee with input below to support adding new comment.
In my directive I try to write a new element or delete all of the depends on state flag. When I decide to support many comments I made a sophisticated code with open\closed tags and my dataset inside them. I do this because I would like to have an id for container which can be found a deleted with all children like this:
var feedback = document.getElementById(id);
feedback.remove();
But when angular create and add my element (which is made open) in the output it is closed automatically and all my dataset are represented such as nest elements. Below I show just a simplified example what I have right now:
var closeTag = angular.element(
'<div>' +
'<input id="name" type="text" ng-model="feedbackValue" ng-minlength="1" required>' +
'<input add-new-team type="submit" value="Add new feedback">' +
'</div>' +
'</td>' +
'</tr>' +
'</div>'
);
return {
restrict: 'A',
controller: function($scope, $element, $attrs) {
$scope.state = 'off';
$scope.toggle = function() {
$scope.$apply(function() {
console.log($element.children().length);
var name = $element.children()[0].attributes["data-value"].value;
var feedbackSet = teamSharedObj.feedback[name];
var id = "feedBackFor" + name.replace(/\s+/g, '');;
var openTag = angular.element(
'<div id=' + id + '>' +
'</tr><tr>' +
'<td colspan="4">'
);
$compile(openTag)($scope);
$element.after(openTag);
$scope.state = ($scope.state === 'on' ? 'off' : 'on');
if ($scope.state === "on") {
console.log("Feedback " + feedbackSet);
if (typeof feedbackSet === "undefined") {
var noFeedback = angular.element(
'<div id="feedbackContainer">' +
"No information. Does he work on any project?" +
'</div>'
);
$compile(openTag)($scope);
$element.after(openTag);
$compile(noFeedback)($scope);
openTag.after(noFeedback);
$compile(closeTag)($scope);
noFeedback.after(closeTag);
return;
}
// // TODO show all feed rows, setup id as a name
} else {
// TODO destroy a div container as a name
console.log("state is off");
var feedback = document.getElementById(id);
feedback.remove();
}
});
};
this.getState = function() {
return $scope.state;
};
},
link: function( scope, element, attrs ) {
element.bind('click', function() {
scope.toggle();
});
}
The question is how to show and maintain collection of elements from directive dynamically and how to delete them? Do you now simpler or more natural way for angular to do that?

Angularjs How to push the new value for the scope object once it is used in the directives

I want to push the new values for my main scope object through the directives.
please advise me how to do that.
In my sample I am using $scope.saveNew function for this but it is not working.
it throw the error "Error: $scope.users is undefined"
myApp.directive("userName", function() {
var editorTemplate = '<td class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
'Add New' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="newValue.name">' +
'<input ng-model="newValue.phone">' +
'Save' +
' or ' +
'cancel.' +
'</div>' +
'</td>';
return {
restrict: "A",
template: function(element, attrs) {
if(attrs.type=='add'){
return editorTemplate;
}
else{
return editorTemplate1;
}
},
scope: {
value: "=userName"
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
$scope.saveNew = function() {
$scope.users.push({name:$scope.newValue.name,phone:$scope.newValue.phone});
$scope.disableEditor();
};
}
};
});
That's because $scope.users was not defined.
Before pushing objects into it, you should initialize it outside saveNew function:
$scope.users = [];
You are creating an isolated scope through scope: { .. }. This means that your directive's scope wont' prototipically inherit from the parent scope. There are two fixes to this situation:
First solution:
If you think that your directive should be isolated, pass users to your directive as you do for userName.
Second solution:
If you wish to access the parent's scope users variable, set scope to true. However, be aware that every instance of your directive will share the same users object/array.

Resources