I have an ng-repeat for an array of users, and I want to be able to click on each user to display their detailed profile information in an Ionic Modal.
Here's the actual HTML:
<div ng-repeat='user in users track by $index' ng-click="openModal()">
<div class="col">
<div class="col profile-image" >
<img src="img/default_user.jpg" class="connect_image" /><br />{{user.name}}<br />
<span class="connect_subject">{{user.about}}</span>
</div>
</div>
</div>
And here's a sample Modal inside that template:
<script id="profile-modal.html" type="text/ng-template">
<div class="modal">
<ion-header-bar>
<h1 class="title">{{user.name}}</h1>
</ion-header-bar>
</div>
</script>
The question is, how do I pass the ng-repeat user variable into the modal, so I can access user.name?
You just have to apply the OpenModal() function to a particualr user, here is the code
<div ng-repeat='user in users track by $index' >
<div class="col">
<div class="col profile-image" ng-click="openModal(user)">
<img src="img/default_user.jpg" class="connect_image" />
<br />{{user.name}}
<br />
<span class="connect_subject">{{user.about}}</span>
</div>
</div>
</div>
And in function you can apply to the scope,
$scope.openModal = function(user) {
$scope.user = user;
$scope.modalCtrl.show();
};
Here is the working Codepen
You can pass $scope of parent controller to modal controller like that;
$ionicModal.fromTemplateUrl('my-modal.html', {
scope: $scope
});
Then you can use your parent scope's data in modal controller. And I saw now. You want to pass your user data that is in ngRepeat to modal controller.
In this case, your code should be the following;
$ionicModal.fromTemplateUrl('modal.html', {
scope: $scope
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function(data) {
$scope.selectedUser = data;
$scope.modal.show();
}
Then, you can use your selected user data with selectedUser.
And you can take a look that.
Related
I thought this should be something easy because I've done it before, but apparently the first time I got lucky, either that or Angular has some quirks I have not yet wrapped my head around.
What I'm trying to do is be able to edit a customer order. All customer orders are sent to the client from the database as JavaScript objects, using PHP.
That is fine, my problem is within Angular when I want to edit these orders, through a modal window (which has its own scope). Basically a form pops up in the modal that asks the user to edit the Javascript object, of course however no user wants to edit a raw object so it's a form with ng-models tied to that object. My problem is the ng-model doesn't seem to pick up my object reference.
So here we go (I have a plunker below):
This is the controller that fetches the customer order on the page the first time (before the user initiates the modal to edit the order):
controller: function($scope,$http,$stateParams,$uibModal) {
$http({
method: 'GET',
url: 'http://example.com/orderDATA',
params: {id: $stateParams.id}
}).then(function successCallback(html) {
html.data[0].orderProperties = JSON.parse(html.data[0].orderProperties); //format data from server so that JavaScript can play with it
$scope.order = html.data[0];
$scope.edit = function (order) //function that launches modal window
{
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'EditOrderInstance.html',
controller: 'EditOrderCtrl',
scope: $scope,
size: "lg",
resolve: {
order: function() {
return order;
}}
});
}
});
}
The edit() function is called like so from the following template:
<div class="container" style="margin-top:2%;">
<div class="row">
<div class="col-xs-12" style="text-align:center;">
<p class="whiteNoPointy">Customer Name : #{{order.orderProperties.firstName + " " + order.orderProperties.lastName}}</p>
</div>
<div class="col-xs-12" style="text-align:center;">
<p class="whiteNoPointy">Pickup : #{{order.orderProperties.pickupDate + " in " + order.orderProperties.location}}</p>
</div>
<div class="col-xs-12" style="text-align:center;">
<p class="whiteNoPointy"><i class="fa fa-envelope" aria-hidden="true"></i> : #{{order.orderProperties.email}}</p>
</div>
<div class="col-xs-12" style="text-align:center;">
<p class="whiteNoPointy"><i class="fa fa-phone" aria-hidden="true"></i> : #{{order.orderProperties.phone}}</p>
</div>
<div class="col-xs-12" style="text-align:center;">
<button type="button" style="border-radius:0;" class="btn btn-warning" ng-click="edit(order)">Edit This Order</button> <button type="button" style="border-radius:0;" class="btn btn-danger">Delete or Refund This Order</button> <button type="button" style="border-radius:0;" class="btn btn-primary">Complete This Order</button>
</div>
</div>
</br></br>
<div class="shipping whiteNoPointy text-center" ng-repeat="specific in order.order">
<div class="col-xs-12" ng-if="specific.quantity.value>0"><p>#{{specific.quantity.value}} #{{specific.Name}}</p></div>
</div></div>
This part works fine. However, when I do hit the edit function, that takes us into a new scope and a new controller, specifically the one below:
app.controller('EditOrderCtrl', ['$scope', '$http', '$uibModal','$uibModalInstance', 'order', function($scope, $http, $uibModal, $uibModalInstance, order) {
$scope.order = order;
So as is hopefully clear, all I did was pass the order object to the modal.
Now to me, all I've done is pass the same order object around, and now to this new controller. But the problem is that when I investigate this latest order it has no $$hashkey. I say this because of the problem that follows, as I said I did this before except in that instance I passed the order object from inside an ng-repeat, and the last step worked. But here when I do it it doesn't work.
What I mean is, when I try to have the models in the modal template line up with the order object passed to the modal's controller, they don't. I just get blank inputs, which isn't good because to edit a customer order you need to now what the current order is, otherwise it's like you are starting over.
Here is the template with the ng-model.
<script type="text/ng-template" id="EditOrderInstance.html">
<div class="modal-header" style="text-align:center;">
<h3 class="modal-title">Edit Order</h3>
</div>
<div class="modal-body" style="text-align:center;">
<form name="order" novalidate>
<label for="firstName">First Name</label>
<input type="text" name="firstName" class="form-control" ng-model="order.orderProperties.firstName" ng-minlength="2" required>
<p ng-show="orderorderProperties.firstName.$error.minlength" class="warning">Please put your full first name.</p>
</div>
<button ng-disabled="order.$invalid||totalPrice===0" ng-click="submitOrder()" class="btn btn-default">Submit</button>
</form>
</div>
<div class="modal-footer" style="text-align:center;">
<button class="btn toggledz" type="button" ng-click="save()">Submit</button>
<button class="btn" type="button" ng-click="cancel()">Cancel</button>
</div>
</script>
Notice the order.orderProperties.firstName ng-model. This is there, I console log it from the modal's controller and I can see it is set, but the model is blank. So why is this the case? Why did it work before when the console.log() showed the object was passed with a $$hashkey? I can't pass from an ng-repeat again because I only have one order, so there is nothing to iterate over in the first template.
Please assist. I need to be able to edit the order using ng-model, so that the admin can edit the order and send a new order object back to my server.
Edit: Added a plunker: https://plnkr.co/edit/x6FPiS6OtF2gdn4ZtFyJ?p=preview
From the first look, the problem appears to be with your resolve function
controller: function($scope,$http,$stateParams,$uibModal) {
$http({
method: 'GET',
url: 'http://example.com/orderDATA',
params: {id: $stateParams.id}
}).then(function successCallback(html) {
html.data[0].orderProperties = JSON.parse(html.data[0].orderProperties); //format data from server so that JavaScript can play with it
$scope.order = html.data[0];
$scope.edit = function (order) //function that launches modal window
{
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'EditOrderInstance.html',
controller: 'EditOrderCtrl',
scope: $scope,
size: "lg",
resolve: {
order: function() {
return $scope.order;
}}
});
}
});
}
Your resolve function for order should return $scope.order
Try it and let me know if this works. I am just going with the instincts
I got it to work by changing the variable name, I guess for some reason it was looking to the old $scope.order instead of the one resolved to the modal?
Anyway, here is a working plunker...
https://plnkr.co/edit/AZpeFGaBktFjSr2SL2Rv?p=preview
Here is my controller:
(function () {
'use strict'
angular
.module('inspinia')
.controller('myController', myController);
myController.$inject = ['$scope', '$uibModal'];
function myController($scope, $uibModal) {
function openModal() {
var modalInstance = $uibModal.open({
templateUrl: 'my_path/modal.html',
scope: $scope
});
};
}
})();
I have a button that opens the modal when calling openModal.
Here is my modal template:
<div class="inmodal" ng-controller="modalController">
<div class="row">
<form name="myForm" ng-submit="processForm()" ng-validate="" class="p-lg">
<div id="form-views" ui-view></div>
</form>
</div>
</div>
Here is the problem: when I open the modal with the form tag inside it I don't get the template that I'm expecting, I'm getting the page from where I am inside the modal. But when I comment the entire form, everything goes OK, but I need this form :)
What could be going on? There are no errors been shown in the console.
<div class="inmodal" ng-controller="modalController">
<div class="row">
<!--<form name="myForm" ng-submit="processForm()" ng-validate="" class="p-lg">
<div id="form-views" ui-view></div>
</form>-->
</div>
</div>
That works.
I'm new with angular. If any info is missing, please tell me :)
That's the modal I'm using.
EDIT
Actually, the problem is with <div id="form-views" ui-view></div>, this div is used with this wizard.
I would like a directive that dynamically knows if I'm following the user in my App.
I have a resource to get the currentUser
this.following = function () {
var defer = $q.defer();
var user = $cookies.getObject('currentUser');
UserResource.get({id: user.id}).$promise.then(
function (data) {
defer.resolve(data.following);
});
return defer.promise;
};
This is in one of my services. It returns all users that I'm following.
When instantiating my controller I fetch the users I follow within my app:
UserService.following().then(
function (data) {
$scope.following = data;
});
I would like to move that into a directive so that I can easily reuse it somewhere else in my app.
This is the HTML I am using right now (and it's not really beautiful) :
<div class="item" ng-repeat="user in users">
<div class="right floated content">
<div ng-show="isFollowing(user)" class="ui animated flip button" tabindex="0"
ng-click='unFollow(user)'>
<div class='visible content'>
Following
</div>
<div class="hidden content">
Unfollow
</div>
</div>
<div ng-hide="isFollowing(user)" ng-click="follow(user)" class="ui button">Follow</div>
</div>
</div>
But instead something like :
<div class="item" ng-repeat="user in users">
<um-follow-button um-user="user"></um-follow-button>
</div>
then depending if I'm following the user or not then render one of the two options.
I don't know if I will have to use a controller in my directive.
I have looked at : https://gist.github.com/jhdavids8/6265398
But it looks like a mess.
I'm listing my schedule entries, now I'm trying to display a modal when clicking on edit for a specific entry. My goal is to be able to edit the values of my entries. But first, can't get the modal to even display
See my plunker or code below
html
<div class="container" ng-app="appUserSchedule">
<div ng-controller="CtrlUserSchedule" >
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">User Schedule</div>
<div class="panel-body">
<div ng-cloak style="max-width:400px;">
<header>
<h3>User schedule</h3>
</header>
<ul>
<li ng-repeat="x in userscheds">{{x.week_day}} {{x.time_start}}-{{x.time_end}}
<span ng-click="showModal($index)" style="cursor:pointer;">Edit</span>
<span ng-click="removeItem($index)" style="cursor:pointer;">Delete</span>
</li>
</ul>
<div>
<div>
<div>
<input placeholder="Add user schedule entry here" ng-model="addMe">
</div>
<div>
<button ng-click="addItem()">Add</button>
</div>
</div>
<p>{{errortext}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="modalContent.html" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Edit</h4>
</div>
<div class="modal-body">
<timepicker ng-model="dt1" hour-step="1" minute-step="15" show-meridian="true"></timepicker>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div> <!-- ng-controller -->
</div> <!-- ng-app -->
js
var app = angular.module("appUserSchedule", []);
app.controller("CtrlUserSchedule", function($scope,$http,$location) {
$http.get('userschedule.json').success(function(data, status, headers, config) {
$scope.userscheds = data.userschedules;
console.log(data);
}).error(function(data, status, headers, config) {
console.log("No data found..");
});
$scope.addItem = function () {
$scope.errortext = "";
if (!$scope.addMe) {return;}
if ($scope.userscheds.indexOf($scope.addMe) == -1) {
$scope.userscheds.push($scope.addMe);
} else {
$scope.errortext = "The item is already in your list.";
}
}
$scope.removeItem = function (x) {
$scope.errortext = "";
$scope.userscheds.splice(x, 1);
}
$scope.showModal = function (action, x) {
var modalInstance;
modalInstance = $modal.open({
templateUrl: 'modalContent.html',
controller: 'CtrlUserSchedule',
scope: $scope
});
// This code for later
// Save User Schedule Entry after making a change, then close modal
saveUserScheduleEntry = function(event) {
$http.put('').success(function(eventsuccess){
}).error(function(err){
/* do something with errors */
});
modalInstance.close();
};
// This code for later
// Close modal
closeUserScheduleEntry = function(event) {
$http.put('').success(function(eventsuccess){
}).error(function(err){
/* do something with errors */
});
modalInstance.close();
};
}
});
ng-repeat creates its own scope, hence the scope of your controller and the scope inside of the ng-repeat is not the same.
therefore $scope.showModal will not be defined inside of the ng-repeat.
the main mistake you are doing here is the "there always has to be a dot in there" rule.
look here:
Why don't the AngularJS docs use a dot in the model directive?
i would recommend to take a little tutorial about the most made angularjs mistakes first, because indeed there is some stuff to know about angularjs before you stop running into little traps like this.
furthermore you did not inject $modal to your controller which should lead in an error like $modal is undefined or something like that.
also you didn't even create/add the corresponding html file you are about to open.
and last but not least you didn't add any dependencies to your angular module regarding bootstrap. so your app won't be able to use/inject $modal anyhow.
see a working plunkr here:
http://plnkr.co/edit/rOjXt1C4E6lHRXUqHdHq?p=preview
have a look at the line where i am "putting the dot in"
$scope.ctrl = this;
i replaced the templateUrl by a simple template because i think it's enough to give the idea.
in the end i have to say that there was so many things wrong about your code that you really should try to debug more on your own and try to accomplish things more step by step.
since there have been like 4-5 mistakes in it this code barely can be your own, but rather is some random copy&paste stuff from anywhere.
otherwise you could not have accomplished that many different lines of code which don't do anything, sorry.
First is you need to add ui.bootstrap module to you ar angular app and pass $modal to your controller like this
var app = angular.module("appUserSchedule", ['ui.bootstrap']);
app.controller("CtrlUserSchedule", function($scope,$http,$location, $modal) {
Then you need to add modalContent.html. This displays the html inside modal window
This may not be the answer, but make sure showModal is receiving the correct arguments. Appears you are only sending $index.
Would have simply made this a comment, but not quite there on the reputation yet. :-)
.controller('PizzaCtrl', ['$scope','$state','$ionicLoading',
function($scope, $state, $ionicLoading) {
$scope.$emit('menu-refresh-request');
$scope.$on('menu-refresh-response', function(event) {
console.log("pizza");
$scope.$broadcast('scroll.refreshComplete');
$scope.items = $scope.$parent.menu.pizze;
console.log($scope.items[1].price);
$ionicLoading.hide();
});
$scope.doRefresh = function() {
$scope.$emit('menu-refresh-request');
};
}])
The data all checks out. The correct item information is logged to the console. However, the ng-repeat="item in items" directive in my view does not update with the pizza items.
I tried using $scope.$apply and $scope.$digest inside the event listener, but the console threw an error saying the digest was already in progress.
Also worth noting that this controller has two sibling controllers that have identical logic to this one, except for different sections of the menu. The console.log("pizza") statement isn't executed until I click into the state.
Is there a clear reason why my view is not updating?
<ion-refresher pulling-text="Updating Menu..." on-refresh="doRefresh()">
<div class="list menu-list">
<a class="item menu-item" ng-repeat="item in items" ui-sref="menu.pizza-detail({ index: $index })">
<div class="row">
<h3 class="row" ng-bind="item.name"></h3>
<div class="row">
<div class="list-price col col-15">
<h4 class="list-value" ng-bind="item.price"></h4>
</div>
<div class="list-description col col-85">
<p ng-bind="item.description"></p>
</div>
</div>
</div>
</a>
</div>
Instead of using $scope.$apply try to use $timeout angular service.
The $timeout does not generate error like „$digest already in progress“ because $timeout tells Angular that after the current cycle, there is a timeout waiting and this way it ensures that there will not any collisions between digest cycles and thus output of $timeout will execute on a new $digest cycle.
.controller('PizzaCtrl', ['$scope','$state','$ionicLoading', '$timeout'
function($scope, $state, $ionicLoading, $timeout) {
$scope.$emit('menu-refresh-request');
$scope.$on('menu-refresh-response', function(event) {
console.log("pizza");
$scope.$broadcast('scroll.refreshComplete');
$timeout(function(){
$scope.items = $scope.$parent.menu.pizze;
});
console.log($scope.items[1].price);
$ionicLoading.hide();
});
$scope.doRefresh = function() {
$scope.$emit('menu-refresh-request');
};
}])
Turns out the solution to this problem is that I needed to add a missing closing tag to the <ion-refresher> tag.
<ion-refresher pulling-text="Updating Menu..." on-refresh="doRefresh()"></ion-refresher>
<div class="list menu-list">
<a class="item menu-item" ng-repeat="item in items" ui-sref="menu.pizza-detail({ index: $index })">
<div class="row">
<h3 class="row" ng-bind="item.name"></h3>
<div class="row">
<div class="list-price col col-15">
<h4 class="list-value" ng-bind="item.price"></h4>
</div>
<div class="list-description col col-85">
<p ng-bind="item.description"></p>
</div>
</div>
</div>
</a>
</div>