AngularJS: How to get controller in directive to access value in view? - angularjs

So, I'm using a directive which is a form to allow the app user to edit or create users.
When I navigate to users/:id, I'm pulling in a userDetail view which pulls in a directive user-form.
...
<h1>User Detail</h1>
<p>{{ detail.first_name }}</p>
<p>{{ userDetail.last_name }}</p>
<p>{{ userDetail.age }}</p>
<p>{{ userDetail.address }}</p>
<p>{{ userDetail.gender }}</p>
<user-form ctrl="editUser" user-detail="userDetail"></user-form>
This view has a controller which pulls in the userDetail via an ajax call:
userDetail.controller("UserDetailController", ['$http', '$scope', '$routeParams', function($http, $scope, $routeParams) {
function getUser() {
var url = "http://localhost:3000/api/users/" + String($routeParams.id)
$http.get(url).then(function(response) {
$scope.userDetail = response.data;
if (!response.data) {
document.location = '/#!/error'
}
})
}
getUser();
}]);
So I created my directive and its controller is based on the ctrl attribute when I pull in the directive depending on the page I am:
function createUser($scope, $rootScope, $http) {
$scope.submitUser = function(isValid) {
var url = 'http://localhost:3000/api/users'
var data = $scope.user;
var config = 'contenttype';
if (isValid) {
$http.post(url, data, config).then(function(response) {
$scope.users.push(response.data);
});
}
}
}
function editUser($scope, $http, $routeParams) {
setTimeout(function() {
//get $scope.userDetail
//assign $scope.user = $scopeDetail to populate the form with the details to allow editing.
console.log($scope.user);
}, 2000)
}
function userFormDirective() {
return {
scope: { users: '=', userDetail: '=', user: '=' },
name: 'ctrl',
controller: '#',
templateUrl: 'components/userForm/userForm-template.html',
}
}
var app = angular.module('user-management', [
'ngRoute',
'users',
// 'userForm',
'userDetail'
]).directive('userForm', userFormDirective)
.controller('createUser', createUser)
.controller('editUser', editUser);
Here is my userForm template:
<form name="userForm" novalidate ng-submit="submitUser(userForm.$valid)">
<fieldset>
<dl>
<dt><label for="first-name">First Name</label></dt>
<dd><input id="first-name" ng-model="user.first" type="text" required /></dd>
</dl>
<dl>
<dt><label for="last-name">Last Name</label></dt>
<dd><input id="last-name" ng-model="user.last_name" type="text" required/></dd>
</dl>
<dl>
...
So basically, when I go to users/2, it does an AJAX request to get the user details 9Hence, a timeout function). Then, I want the directive's controller to access the models in the view so that I can assign the userDetails that were obtained and assign it to the models in the view, thereby autpopulating it and allowing edits. Not sure if this is a correct way of doing it because I'm rather new to AngularJS.

Related

Reset component value in a form

I have a component which gets initialized with a value got from an ajax request in its controller $postLink event. This component is inside a form.
Then the user may change the default value and then submit. When the form is submitted, the component value becomes blank. I need to find a way to reinitialize back to the value got from the ajax request, but of course the $postLink event cannot fire again since the component has already been created.
Component js:
app.component('formFieldPortafoglioSelector', {
templateUrl: 'ngComponents/form-field-portafoglio-selector.html',
bindings: {
label: '#',
model: '='
},
controller: ['$scope', 'ApiService', function($scope, ApiService) {
var ctrl = this;
ctrl.$postLink = function() {
ApiService.domini.then(function(response) {
$scope.portafogli = response.domini.portafogli;
ctrl.model = $scope.portafogli[0].id_ptf;
});
};
}]
});
Component Template:
<div class="form-group">
<label class="col-form-label col-form-label-sm">{{ $ctrl.label }}</label>
<select class="form-control custom-select"
ng-options="ptf.id_ptf as ptf.des_ptf for ptf in portafogli"
ng-model="$ctrl.model"
>
</select>
</div>
Component Usage:
<div ng-controller="resourceController as rc">
<form ng-submit="rc.operazione.$save()">
<form-field-portafoglio-selector model="rc.operazione.id_ptf_sorgente" label="Portafoglio Sorgente">
</form-field-portafoglio-selector>
</form>
</div>
The Resource Controller is defined as follows:
app.controller('resourceController', ['$scope', '$resource', function($scope, $resource) {
this.operazione = new $resource('operazioni', null, {})();
}]);

Angular bootstrap modal not working

I am working on angular application where I am displaying pop up message using bootstrap modal.
but its not displaying dynamic header text and body text.Pop up is showing but with blank header and body.
my main controller is as below
var requestUserController = function ($scope, $window, $uibModal, DataService) {
$scope.modalOptions = {
headerText: "",
bodyText: ""
}
var onServerError = function (data) {
$scope.modalOptions.headerText = "Error";
$scope.modalOptions.bodyText = data.statusText;
var serverModel = $uibModal.open({
templateUrl: window.serverUrl + 'app/ErrorMessages/PopUpErrorMessage.html',
controller: 'requestUserController',
scope: $scope
});
$scope.cancelForm = function () {
serverModel.close();
};
};
var onClientDataComplete = function (data) {
//window.hideProgress();
$scope.requestUser.clientDrp = data;
$scope.clientSelected = $scope.requestUser.clientDrp[0];
};
//window.showProgress();
DataService.getListofClients()
.then(onClientDataComplete, onServerError);
}
App.controller("requestUserController", ["$scope", "$window", "$uibModal", "DataService", requestUserController]);
and html for modal is
<div class="modal-header" ng-class="{true: 'alert-success', false: 'alert-danger'}[modalOptions.headerText == 'Success']">
<h3>{{modalOptions.headerText}}</h3>
</div>
<div class="modal-body">
<p>{{modalOptions.bodyText}}</p>
</div>
<div class="modal-footer">
<input type="button" class="btn icn-ok" value="Ok"
ng-click="cancelForm()" />
</div>
But pop up is showing blank header and body text
Remove loading of 'requestUserController' from your code and use the following code for open popup window
var serverModel = $uibModal.open({
templateUrl: window.serverUrl + 'app/ErrorMessages/PopUpErrorMessage.html',
scope: $scope
});

AngularJS getting data from controller to directive

I am trying do display data retrieved from database in controller to directive. I am using Controller as syntax, but when i try to display my data in directive it is undefined. I am getting right value for name and example variable, but not for items variable.
TaskCtrl.js
app.controller('TasksCtrl', ['$scope', 'TaskService', function ($scope, TaskService) {
// initialize function
this.newTask = true;
this.name = "My name is Nedim";
this.example = "Example";
this.templates = {
new: "views/task/addTask.html",
view: "views/task/viewTask.html"
};
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
this.items = data.tasks;
});
$scope.$on('newTaskAdded', function(event, data){
this.items.concat(data.data);
});
return $scope.TasksCtrl = this;
}]);
taskList.html
<ul class="list-group">
<li ng-repeat="item in taskCtrl.items" class="list-group-item">
<a ng-click="openItem()">
<span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>
<span>{{item.name}}</span>
<span class="task-description">{{item.description}}</span>
</a>
</li>
</ul>
<div>{{taskCtrl.name}}</div>
<div>{{taskCtrl.example}}</div>
<div>{{taskCtrl.items}}</div>
entityTaskList directive
app.directive('entityTaskList', function(){
return {
restrict: 'E',
templateUrl: 'views/task/taskList.html',
scope: {
items: '='
},
bindToController: true,
controller: 'TasksCtrl as taskCtrl',
link: function(scope, element, attrs){
console.log("items" + scope.items);
scope.openItem = function(){
var ctrl = scope.taskCtrl;
ctrl.newTask = false;
};
}
};
});
task.html
<div class="container-fluid">
<div class="row">
<div class="col-sm-6">
<entity-task-list items="items"></entity-task-list>
</div>
<div class="col-sm-6" ng-controller="TaskDetailCtrl as taskDetailCtrl">
<!-- form for adding new task -->
<div ng-show="taskCtrl.newTask" ng-include="taskCtrl.templates.new"></div>
<!-- container for displaying existing tasks -->
<div ng-show="!taskCtrl.newTask" ng-include="taskCtrl.templates.view"></div>
</div>
</div>
</div>
Looks like you have forgotten to use the controller name for referencing the variable.
So in your directive you have:
controller: 'TasksCtrl as taskCtrl'
Meaning this should be:
<entity-task-list items="taskCtrl.items">
The problem might be this. When you use functions like:
TaskService.loadAllTasks().then(function (data) {
this.items = data.tasks;
});
$scope.$on('newTaskAdded', function(event, data){
this.items.concat(data.data);
});
then this in these functions' body refers to the function's scope rather than the controller's scope, so you're setting properties on the wrong this object.
To avoid this problem you can do one of the following:
option 1:
Use bind. For example:
TaskService.loadAllTasks().then(function (data) {
this.items = data.tasks;
}.bind(this));
$scope.$on('newTaskAdded', function(event, data){
this.items.concat(data.data);
}.bind(this));
option 2:
A common practice in Angular controllers is to save this in a local variable, and then use that variable instead. Example:
app.controller('TasksCtrl', ['$scope', 'TaskService', function ($scope, TaskService) {
// initialize function
var vm = this;
vm.newTask = true;
vm.name = "My name is Nedim";
vm.example = "Example";
vm.templates = {
new: "views/task/addTask.html",
view: "views/task/viewTask.html"
};
// load all available tasks
TaskService.loadAllTasks().then(function (data) {
vm.items = data.tasks;
});
$scope.$on('newTaskAdded', function(event, data){
vm.items.concat(data.data);
});
return $scope.TasksCtrl = this;
}]);

AngularJS, Loading spinner directive with transclude?

I want to make a directive with shows a spinner when $http request is executing.
I thought this would be working (e.g. load users):
Main Controller
app.controller('UserListController', function($scope, $http) {
$scope.users = [];
$scope.loading = true;
$http.get('/users').then(function(response) {
$scope.users = response.data;
}).finally(function() { $scope.loading = false; });
});
Template using the directive
<div request-loading="loading">
<ul>
<li ng-repeat="user in users">{{ user.name }}</li>
</ul>
</div>
request-loading-directive.js
app.directive('requestLoading', function() {
return {
scope: {
requestLoading: '='
},
transclude: true, // I think this is not Ok
templateUrl: 'request-loading-directive.html'
};
});
request-loading-template.html
<div ng-show="requestLoading" class="super-cool-spinner">
Loading text with the spinner...
</div>
// This is what is not working
// I thought the content of the users (ul and li) would be render in this div
// when the request is Ok.
<div ng-transclude ng-show="! requestLoading"></div>
Any help would be nice!
Thx.

Initializing controller instance with different data sets in angular

How can I use a different sets of initialization variables for each instance of controller in my app?
in view:
<div ng-controller="showProjectList">
{{project_list}}<!--user 1-->
</div>
<div ng-controller="showProjectList">
{{project_list}}<!--user 2-->
</div>
in controller
myapp.controller('showProjectList',function($http)
{ $scope.project_list= <Here I have a http request with argument user_id to fetch project_list>
}
Now how do I initialize each controller with a different user_id? One solution I have readon stackexchange & on google-groups is the use of ng-init.(link google-grp: https://groups.google.com/forum/#!topic/angular/J6DE8evSOBg) .However the use of ng-init is cautioned against in the same threads. So how do you initialize a controller with data then ?
You could use a combination of a controller, a directive and a service for that matter.
The controller is holding the user id's.
The directive is rendering the project list.
The service is responsible for fetching the data from the server. You could implement a cache and/or use $resource in here.
Here is the template code:
<div ng-controller="Projects">
<!-- here you can put an input element with
ng-model="users" to modify the user list on the fly -->
<div ng-repeat="user in users">
<project-list user="user" />
</div>
</div>
The controller:
myapp.controller('Projects', ['$scope', function($scope) {
$scope.users = [1, 2, 3];
}]);
The directive:
myapp.directive('projectList', ['UserService', function(UserService) {
return {
restrict: 'E',
scope: {
user: "="
},
templateUrl: 'project-list.html',
link: function($scope, $element, $attrs) {
UserService.getUserProject($scope.user).then(function(response) {
$scope.userProjects = response;
});
}
};
}]);
The service:
myapp.factory('UserService', ['$http', function($http) {
var getUserProject = function(user) {
var promise = $http.get('users/' + user + '/project');
return promise;
}
return {
getUserProject: getUserProject
}
}]);

Resources