Can't access form values in a $modalInstance - javascript

I'm opening a $modalInstance in which user has to choose an option from radio inputs (values loaded dynamically) and return chosen value.
I have this function to open the $modalInstance:
$scope.openAddFriendGroup = function () {
var addFriendGroupModal = $modal.open({
templateUrl: "addFriendGroupModal.html",
controller: ModalAddFriendGroupCtrl,
resolve: {
myDetails: function () {
return $scope.info;
}
}
});
};
Then this is the $modalInstance controller:
var ModalAddFriendGroupCtrl = function ($scope, $modalInstance, myDetails, groupsSvc) {
$scope.addableFriends = [];
$scope.chosenFriend = null;
//here goes a function to retrieve value of $scope.addableFriends upon $modalInstance load
$scope.addFriend = function () {
$scope.recording = true;
groupsSvc.addFriend($scope.chosenFriend, myDetails).then(function (response) {
if(response.status && response.status == 200) {
$modalInstance.close($scope.userid);
}
}, function (err) {
$modalInstance.dismiss(err);
});
};
};
And this is addFriendGroupModal.html, the HTML for the modal itself:
<div id="add-friend-group-modal">
<div class="modal-header">
<h3 class="modal-title">Add friend</h3>
</div>
<div class="modal-body">
<form class="form" role="form" ng-hide="loading">
<div class="form-group">
<label class="control-label">Friend:</label>
<div class="radio" ng-repeat="thisFriend in addableFriends">
<label>
<input type="radio" id="friend{{thisFriend.id}}" name="chosenFriend" ng-model="$parent.chosenFriend" ng-value="thisFriend" /> {{thisFriend.name}} {{thisFriend.surname}}
</label>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="addFriend()">Add friend</button>
</div>
</div>
Now, the problem comes when I try to retrieve the value that has been selected in the radio buttons of the form in the modal. I can't seem to retrieve this value in $scope.addFriend. The value of $scope.chosenFriend stays at null and does not get updated when selecting a radio option.
What am I doing wrong?

$modal.open returns promise so try :
var addFriendGroupModal;
$modal.open({ ...})
.result.then(function(response){
addFriendGroupModal = response;
});

<input type="radio" id="friend{{thisFriend.id}}" name="chosenFriend" ng-model="$parent.chosenFriend" ng-value="thisFriend" /> {{thisFriend.name}} {{thisFriend.surname}}
in here your ng-model is $parent.chosenFriend so, why are you expecting $scope.chosenFriend to not be a null? change you ng-model property to $scope.chosenFriend.

Retrieved answer from a related question, by gertas
Angular-UI modals are using transclusion to attach modal content, which means any new scope entries made within modal are created in child scope. This happens with form directive.
This is known issue: https://github.com/angular-ui/bootstrap/issues/969
I proposed the quick workaround which works for me, with Angular 1.2.16:
<form name="$parent.userForm">
The userForm is created and available in modal's controller $scope. Thanks to scope inheritance userForm access stays untouched in the markup.
<div ng-class="{'has-error': userForm.email.$invalid}"}>
So, in my form I would have to set a name="$parent.friendForm" attribute to <form>, and then bind the radio button model to it, ng-model="friendForm.chosenFriend" to be able to read it from the modal scope at $scope.friendForm.chosenFriend.

Related

Unable to validate mutli-select input with AngularJS

I'm new to Angular, and I struggle with validating a multi select input with ngOptions attribute.
I want the field to be required, so the user must chose at least one option. However the validation methods Angular have simply doesn't work in my case, Here's what I've tried:
<form name="products" novalidate>
<div class="form-group">
<label for="select-product">Chose product/s</label>
<select id="select-product" name="selectedProduct" class="form-control"
required
multiple
ng-model="selectedProduct"
ng-options="product.name for product in products">
</select>
</div>
<button class="btn btn-primary pull-left" ng-click="products.selectedProduct.$valid && goToChildrenId()">Next</button>
</form>
Even if I chose a product and I can see that the form class switch from .ng-invalid to .ng-valid, the function goToChildrenId() doesn't run.
Also, if I add {{products.selectedProduct.$valid}} at the bottom, when I refresh the page I can see "false" for a second but it disappear, why?
If it's relevent, this is the controller:
adminCheckout.controller('productsCtrl', function($scope, $http, wpMiniapps, $location, $rootScope){
$scope.products = [];
var url = wpMiniapps.routeUrl("getProducts");
$http.post(url, {}).then(function(res){
$scope.products = res.data.data;
}, function(err){
console.log(err);
});
$scope.$watch('selectedProduct', function (newVal) {
$rootScope.globalData.products = newVal;
});
$scope.goToChildrenId = function(){
$location.path('/select-children');
};
});
I searched the web but nothing seems to work in my case.
I will really appreciate any help.
You have a variable name collision which is causing the problem: the form is named products and this ends up as a $scope variable. But it collides with $scope.products = [] from the controller. Simply renaming the form to, e.g., productsForm solves the problem:
<form name="productsForm" novalidate>
...
<button class="btn btn-primary pull-left" ng-click="productsForm.selectedProduct.$valid && goToChildrenId()">Next</button>
</form>

Event in Angular Controller Only Fires Once

I'm trying to implement an Angular version of an autocomplete textbox. I found some working examples, but none seem to exhibit the behavior I'm getting.
The autocomplete functionality itself works fine. When a suggested item is selected, the control correctly handles the selection. Subsequent uses of the control (typing in the autocomplete box, making a selection) fail to engage the 'selected' event/condition, although the autocomplete bit continues to work.
Here's my module & controller:
var app = angular.module('myapp', ['angucomplete-alt']); //add angucomplete-alt dependency in app
app.controller('AutoCompleteController', ['$scope', '$http', function ($scope, $http) {
//reset users
$scope.Users = [];
$scope.SelectedUser = null;
//get data from the database
$http({
method: 'GET',
url: '/UserRoleAdministration/Autocomplete'
}).then(function (data) {
$scope.Users = data.data;
}, function () {
alert('Error');
})
//to fire when selection made
$scope.SelectedUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}
}]);
I'm guessing the problem is in there, but I don't know what it is. I include the bit from my view below, although there doesn't seem to be much there to fuss with:
<div class="form-group">
<div ng-app="myapp" ng-controller="AutoCompleteController">
<div angucomplete-alt id="txtAutocomplete" pause="0" selected-object="SelectedUser" local-data="Users" search-fields="RegularName" placeholder="People Search" title-field="RegularName" minlength="2" input-class="form-control" match-class="highlight"></div>
<!--display selected user-->
<br /><br />
<div class="panel panel-default" id="panelResults">
<div class="panel-heading"><h3 class="panel-title">Manage Roles for {{SelectedUser.RegularName}}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-md-2">
<img src="~/Images/avatar_blank.png" width="100%" />
</div>
<div class="col-md-4">
<div class="row">
<div class="col-md-4">Selected User:</div> <div class="col-md-6">{{SelectedUser.RegularName}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
Any help would be appreciated!
UPDATE
After fixing the mistake Yaser pointed out, I wasn't getting any information regarding the selected object. So I set the page to output the entire object, rather than the specified fields, and I noticed I was getting information about the selected object, and on subsequent attempts as well.
So this worked: {{SelectedUser}}
This did not: {{SelectedUser.Department}}
Then I looked at the object and noticed its format. It had "title" and "description", and description had inside it the key/value pairs.
So now this works: {{SelectedUser.description.Department}}
And that's it.
Because the first time you are setting $scope.SelectedUser as a function but inside that you are rewriting the same one with an object. so next time it is not a function any more, try to rename the function:
$scope.setUser = function (selected) {
if (selected) {
$scope.SelectedUser = selected.originalObject;
}
}

Getting user input text with $watch in AngularJS not working on ng-if

I have a cross platform app built using AngularJS, Monaca and OnsenUI.
I have a login view that checks if the user has logged in before by querying a SQLite database. Based on whether there is data in the database, I display a welcome message to the user OR I display the login text field.
I have a method that queries the SQLite database and this is working as intended. When a entry is found on the database I set a boolean value to display the welcome message - else the boolean displays the login text field.
On my view I do the following;
<!-- User not in DB -->
<div ng-if="showLoginUI">
<div class="input">
<input type="password" placeholder="User ID" ng-model="userID"/>
</div>
</div>
I watch for changes in the text field to save the user input, but no actions are registered in the example as above. This is my method to register user action on the text field.
$scope.$watch("userID", function (newVal, oldVal)
{
if (newVal !== oldVal) {
$scope.newUserID = newVal; // Not getting here
}
});
However, when I remove the ng-if from the example above - the user events are registered. How do I keep my ng-if while still registering events on the text-filed?
I tried adding a $timeout to my $watch function but this did not help either.
It happens because ngIf directive creates a child $scope.. the problem is that you're using ng-model without the Dot Rule or controller-as-syntax.
The whole problem was already explained by Pankaj Parkar in this question.
So, to make it work, you have to create a new object, ex:
$scope.model = {};
Then, build your ng-model like this:
ng-model="model.userID"
Take a look on this simple working demo:
angular.module('app', [])
.controller('mainCtrl', function($scope) {
$scope.model = {};
$scope.$watch("model.userID", function(newVal, oldVal) {
if (newVal !== oldVal) {
$scope.model.newUserID = newVal;
}
});
});
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<button type="button" ng-click="showLoginUI = !showLoginUI">Hide/Show</button>
<div ng-if="showLoginUI">
<div class="input">
<input type="password" placeholder="User ID" ng-model="model.userID" />
</div>
</div>
<div ng-if="model.newUserID">
<hr>
<span ng-bind="'Working: ' + model.newUserID"></span>
</div>
</body>
</html>

2-way binding is lot when using $templateRequest

I have a template, which is loaded using $templateRequest. I have a textarea in the template. The textarea populates the value, that is set in the controller. But when I am trying to access the textarea in the controller method, it does not update the value.
Template
<div class="panel add-notes">
<div class="panel-body">
<textarea ng-model="quickNote" rows="5"/>
<button ng-click="saveNotes()">Add Note</button>
</div>
</div>
</div>
Method to load the template
$scope.displayPanel = function(templateName){
var templateURL = resourceURL+templateName+".html";
$templateRequest(templateURL).then(function(template) {
$compile($("#modalContent").html(template).contents())($scope);
},function() {
//ERROR HANDLER
});
};
Controller Method
$scope.saveNotes = function(){
console.log($scope.quickNote);
}
In the console log, the value of quickNote is displayed as undefined. Any resolution?

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

Categories

Resources