I am using the following versions:
- Ionic, v1.0.0-beta.14
- AngularJS v1.3.6
Route configuration:
myApp.config(function ($stateProvider) {
$stateProvider
.state('manager_add', {
url: '/managers/add',
templateUrl: 'app/components/mdl.role_members/views/add.html',
controller: 'ManagerAddController'
});
});
Controller configuration:
myApp.controller('ManagerAddController', function ($scope, $state, $ionicLoading, $filter, ContactService, ManagersService, RoleRequest, RoleRequestsSentService, ToastrService) {
$scope.role_request = RoleRequest.new();
$scope.showContactSearch = false;
$scope.managers = ManagersService.collection();
$scope.$watchCollection("managers", function( newManagers, oldManagers ) {
if(newManagers === oldManagers){ return; }
$scope.managers = newManagers;
$scope.contactsToBeInvited = getNotInvitedContacts();
});
$scope.contacts = ContactService.collection();
$scope.$watchCollection("contacts", function( newContacts, oldContacts ) {
if(newContacts === oldContacts){ return; }
$scope.contacts = newContacts;
$scope.contactsToBeInvited = getNotInvitedContacts();
});
$scope.contactsToBeInvited = getNotInvitedContacts();
function getNotInvitedContacts() {
var notinvited = [];
angular.forEach($scope.contacts, function(contact) {
if(angular.isObject($scope.managers)) {
var results = $filter('filter')($scope.managers, {member_id: Number(contact.contact_id)}, true);
if (results.length == 0) {
this.push(contact);
}
} else {
this.push(contact);
}
}, notinvited);
return notinvited;
}
$scope.search_contact = "";
$scope.search = function(contact) {
if($scope.search_contact === "" || $scope.search_contact.length === 0) {
return true;
}
$scope.showContactSearch = true;
var found = false;
if(contact.display_name) {
found = (contact.display_name.toLowerCase().indexOf($scope.search_contact.toLowerCase()) > -1);
if(found) { return found; }
}
if(contact.contact.getFullName()) {
found = (contact.contact.getFullName().toLowerCase().indexOf($scope.search_contact.toLowerCase()) > -1);
if(found) { return found; }
}
if(contact.contact.email) {
found = (contact.contact.email.toLowerCase().indexOf($scope.search_contact.toLowerCase()) > -1);
if(found) { return found; }
}
return found;
}
$scope.selectContact = function(contact) {
$scope.search_contact = contact.contact.getFullName();
// TODO: Make dynamic role
$scope.role_request.role_id = 4;
$scope.role_request.email = contact.contact.email;
};
$scope.addRoleMember = function(valid) {
if($scope.role_request.email === "") { return; }
if(!valid) { return; }
$ionicLoading.show({
template: 'Please wait...'
});
RoleRequestsSentService.add($scope.role_request).then(function(roleJsonResponse){
ToastrService.toastrSuccess('Request send', 'We have send an invite to '+ $scope.search_contact +'.');
$ionicLoading.hide();
$state.go('managers');
});
}
});
View configuration:
<ion-view view-title="ManagerAdd" >
<ion-content class="has-header scroll="true">
<div class="content">
<div class="list">
<div class="item item-border">
<p>Some text</p>
</div>
</div>
<form name="managerForm">
<div class="list">
<div class="item item-divider">
Some text
</div>
<div class="item item-border">
<form name="fillForm">
<div class="form-group">
<label class="item item-input item-stacked-label item-textarea">
<span class="input-label border-none">Personal message: <span class="text-red required">*</span></span>
<textarea name="message" ng-model="role_member.message" required></textarea>
</label>
<p ng-show="managerForm.message.$dirty && managerForm.message.$error.required"
class="error-message">Message required!</p>
</div>
<div class="form-group">
<label class="item item-input">
<span class="input-label">Search on name <span class="text-red required">*</span></span>
<input type="text" name="search_contact" ng-model="$parent.search_contact">
</label>
<div class="searchResultBox" ng-show="showContactSearch">
<ion-scroll direction="y" class="scrollArea">
<div class="list">
<a class="item item-border item-avatar pointer" ng-repeat="contact in $parent.filteredContacts = (contactsToBeInvited | filter:search:false)" ng-click="$parent.selectContact(contact)">
<img src="{{ contact.getImage('thumbnail') }}">
<h2>{{contact.getIconName()}}</h2>
<p>City: {{contact.contact.city}}</p>
</a>
</div>
</ion-scroll>
<div class="notFound pointer" ng-hide="filteredContacts.length">
<h3>Nobody found</h3>
<p>You can only search through existing contacts</p>
</div>
</div>
</div>
</form>
</div>
</div>
<div class="form-actions">
<button type="submit" class="button button-block regie-button" ng-click="addRoleMember(registerForm.$valid)">
Sent request
</button>
</div>
</form>
<p class="text-red" style="text-align:center; font-size:14px; font-weight: 400;">* required</p>
</div>
</ion-content>
</ion-view>
As you can see in the view I need to use $parent
to the following fields to get it to work:
ng-model="$parent.search_contact"
ng-repeat="contact in $parent.filteredContacts = (contactsToBeInvited | filter:search:false)"
ng-click="$parent.selectContact(contact)"
I really don't understand why this is necessary because the complete view is using the same controller. Does anyone have an idea?
The problem is the inheritance. Between your controller's scope and those fields, there are several new scopes (ion-content, ion-scroll and probably others).
So for example the
ng-model="search_content"
. When you write in there, it is going to create asearch_content
variable inside theion-content
scope (or an intermediary scope if there is any that I didn't see). Sincesearch_content
is being created insideion-content
, your controller won't see it.If you do
$parent.search_content
it will create it in the parent content (AKA the controller's scope).You shouldn't do that, what
$parent
is for you today, tomorrow it can point to anything else (because you could add a new scope in between without knowing it so $parent will then point to theion-content
.So instead of doing that, you need to use objects and no primitives, for example:
Thank to that, it will look for the
form
object through the prototype chain until it finds it on the controller's scope and use it (just what you need).Read this which is hundred times better than my explanation.
This is a very typical angular scoping issue. Ion-view creates a new child scope and uses prototypical inheritance: https://github.com/angular/angular.js/wiki/Understanding-Scopes
Three are several ways to solve: