I trying to build a feedback system with Angular. I am using angular ui router to route the user to different pages. It has basically 3 screens(see below).
Satisfied / Not satisfied links with icon.
A form for satisfied user to fill.
A form for unsatisfied user to fill.
I have succeeded in implementing it mostly. But am not able to figure out how to do 1 thing. I want to time out the form if some one leaves it without submitting it and send go back to the 1st screen, so next user can give feedback. But at the same time, I don't want give a flat timer as I don't want the form to redirect if someone is filling the form say slowly. So the timer should redirect to the form to first screen if no activity is happening. But the timer should reset each time the user interact with the form.
Routes:
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// route to show main page with satisfied/unsatisfied
.state('main', {
url: '/main',
templateUrl: 'container.html',
controller: 'formController',
})
//satisfied
.state('main.happy', {
url: '/happy',
// data: { happy: true },
templateUrl: 'happy.html',
})
//not satisfied
.state('main.sad', {
url: '/sad',
templateUrl: 'welcome.html'
})
// catch all route
$urlRouterProvider.otherwise('/main');
})
The form code below:
<form id="signup-form" ng-submit="processForm()" >
<div class="col-md-12"><h4 class="col-md-12" >What made you satisfied</h4></div>
<div class="form-group col-md-12">
<div class="row">
<div class="radio col-md-6">
<label>
<input type="checkbox" ng-model="formData.option1" >
Option1
</label>
</div>
<div class="radio col-md-6">
<label>
<input type="checkbox" ng-model="formData.option2" >
Option2
</label>
</div>
</div>
</div>
<div class="col-md-12 contact">
<h4 class="col-md-12" >Want us to contact you?</h4>
<div class="form-group">
<div class="textbox col-md-12">
<label>Name </label>
<input type="text" ng-model="formData.name" >
</div>
<div class="textbox col-md-12">
<label>Email </label>
<input type="text" ng-model="formData.email" >
</div>
</div>
</div>
<div class="form-group row">
<div class="col-md-12 ">
<div class="col-md-12 contact">
<button type="submit" class="btn btn-primary" >Submit</button>
</div>
</div>
</div>
</form>
Here is a timeout function(you might could use $timeout as well) that I wrote to do something similar. It will allow the function to run for a set amount of time, and reset if a change has occurred to the scope of the timeout:
function TimeOut(fn, interval, scope, args) {
scope = scope || window;
var self = this;
var wrap = function() {
self.Clear();
fn.apply(scope, args || arguments);
};
this.Id = setTimeout(wrap, interval);
TimeOut.prototype.Id = null;
TimeOut.prototype.Cleared = false;
TimeOut.prototype.Clear = function() {
clearTimeout(this.Id);
this.Cleared = true;
this.Id = null;
}
}
I was using this to send some data to the server after a toggle is flipped, but I did not want it to fire if the user repeatedly flipped the switch. To Use this function you do something similar to this (Starting it on page load):
$scope.yourTimer = new TimeOut( SomeFunction($scope.someObject),
someInterval, yourScope, arg)
NOTE: I passed in window.parent for yourScope so the function will fire regardless if user left page. Yous do not need to pass in the args if you do not have any
Now what you need to do is add a watch/watchcollection to your form data and in this watch you do this:
$scope.$watchCollection( "yourData",
function( newValue, oldValue ) {
if(newValue != oldValue){
if(!($scope.youtTimer.Cleared === true && $scope.yourTimer === null){
$scope.yourTimer.Clear()
$scope.yourTimer = new TimeOut( SomeFunction($scope.someObject),
someInterval, yourScope, arg)
}else{
//recreate time just in case
$scope.yourTimer = new TimeOut( SomeFunction($scope.someObject),
someInterval, yourScope, arg)
}
}
}
);
Now if any thing changes in the "yourData", before the timer elapses, the current timeout is cleared and restarted again.
Related
I am using two controllers. When changes happen in one controllers it should get changed immediately in the other controller. I am using the $broadcast event to achive this.
My code:
My First controller
app.controller('configurationCtrl', function($scope, $http,Notification,$rootScope,$cookies) {
$scope.awssubmit=function(){
$scope.page_loader=true
$http.post("/insert_config_details",$scope.userdata).then(function(List){
if(List){
$scope.page_loader=false;
$cookies.put("bucket",$scope.userdata.bucket_name)
$scope.$broadcast('eventEmitedName', 'Some data');
Notification.success('<span class="glyphicon glyphicon-ok"></span> <strong>AWS Configuration details updated successfully.</strong>');
}
else{
$scope.page_loader=false;
Notification.error('<span class="glyphicon glyphicon-ok"></span> <strong>Error!!! Please try again later.</strong>');
}
$scope.awssave = false;
$scope.awstext=true;
})
}
});
My Second Controller:
app.controller('SidemenuController', function($scope, $http,$location,BucketService)
{
$scope.$on('eventEmitedName', function (event, data) {
console.log("Called"); //I am not getting this
value
console.log(data); // 'Some data' // I am not getting this
value
});
});
aws_submit() is called from my view and everything seems to work fine. But in SidemenuController I am not getting any data. Is there any mistake in my code?
Update:
My view :
<form id="awsform" method="post" name="awsform" class="form-horizontal" novalidate>
<div class="col-sm-6 four_module_config">
<div class="account_settings">
<div class="col-sm-12 heading_config" ng-hide="awssave">
<h4 class="sub_title col-sm-11" style="border-bottom:none">AWS S3 Configurations</h4>
<% if(valid_role[1]) { %>
<div class="action col-sm-1">
<span class="actico editrole" ng-click="editaws()">
<a href='javascript:void(0)' ></a>
</span>
</div>
<% } %>
</div>
<div class="col-sm-12 heading_config" ng-show="awssave">
<h4 class="sub_title col-sm-9" style="border-bottom:none">AWS S3 Configurations</h4>
<div class="action col-sm-3 close_config">
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-show="awstest"
ng-click="verifyaws()">Test</button>
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-show="submitawssave"
ng-click="awssubmit()">Submit</button>
<button type="button" class="site_btn submit_btn save_config col-sm-2" id="submit" ng-click="closeaws()">Cancel</button>
</div>
</div>
<div class="ipfield col-md-8 hint_txt_conf">
*Enter your AWS access Key, S3 Bucket name configured in your AWS Environment. Which is used to store your document in the
cloud.
</div>
<div class="ipfield first_ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS access key <span class="mandat">*</span></label>
<input type="password" ng-disabled="awstext" ng-model="userdata.key" required name="key" class="txt_box" id="key" placeholder="Enter AWS access key">
<span toggle="#key" class="fa fa-fw fa-eye field_icon toggle-password"></span>
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Secret Key <span class="mandat">*</span></label>
<input type="password" ng-disabled="awstext" ng-model="userdata.secretkey" required name="secretkey" class="txt_box" id="secretkey" placeholder="Enter AWS Secret Key">
<span toggle="#secretkey" class="fa fa-fw fa-eye field_icon toggle-password"></span>
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Region Code <span class="mandat">*</span></label>
<input type="text" ng-disabled="awstext" ng-model="userdata.region" required name="region" class="txt_box" id="region" placeholder="Enter AWS Region Code">
</div>
</div>
<div class="ipfield">
<div class="col-md-8">
<label for="name" class="usrlabel">AWS Bucket Name <span class="mandat">*</span></label>
<input type="text" ng-disabled="awstext" ng-model="userdata.bucket_name" required name="bucket_name" class="txt_box" id="bucket"
placeholder="Enter AWS Bucket Name">
</div>
</div>
</div>
</div>
</form>
If you want to send data from one controller to another controller using $brodcast than use $rootscope.$broadcast
$rootScope.$broadcast('eventEmitedName', 'Some data');
Second Controller
app.controller('SidemenuController', function($scope, $http,$location,BucketService) {
$scope.$on('eventEmitedName', function (event, data) {
console.log("Called");
console.log(data); // 'Some data'
$scope.bucket = data;
});
});
Note: Do not use $rootscope.$on as listener because $rootscope
listener are not destroyed . Instead it will create listeners stack
If you want to call one controller event into another there are four methods available:
$rootScope.$broadcast() if your controller are not in a parent / child relation.
If your second controller (event fired here) is a parent you can use $scope.$broadcast();
If your second controller (event fired here) is a child you can use $scope.$emit();
The best way to solve this would be to use a service -> Example of using a service to share data between controllers.
Note: You need to destroy $rootScope.$on() listeners manually avoid stacking events. This Difference between $rootScope.$on vs $scope.$on and this Do you need to unbind $scope.$on in $scope $destroy event? will help you understand the basics of using events.
View
<div ng-controller="MyCtrl">
<button ng-click="broadcast()">
broadcast
</button>
</div>
<div ng-controller="MySecondCtrl">
{{ test }}
</div>
AngularJS application
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope, $rootScope) {
$scope.broadcast = function() {
$rootScope.$broadcast('test', 'testit');
}
});
myApp.controller('MySecondCtrl', function($scope, $rootScope) {
var registerScope = $rootScope.$on('test', function(test, args) {
console.log(args);
$scope.test = args;
});
// clean up, destroy event when controller get destroyed.
$scope.$on('$destroy', registerScope);
});
> demo fiddle
I am using angularjs and spring mvc for my application. At first I am displaying all the placements with one button Placed Candidates. I am doing ng-repeat for displaying all the placements.
Here is my html.
<div class="row" data-ng-repeat="placement in placements">
<div class="col-xs-12 col-sm-12 col-md-12">
<h5>{{placement.companyName}}</h5>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<h6>{{placement.placementDate | date:'dd MMM yyyy'}}</h6>
Company Target (appox):10 Achieved:
</div>
<a href="javascript:void(0);" data-ng-
click="placedcandidatespopup(placement.placementId);">//here i can
get particular placementId but how to pass this id to
savePlacementStudents() method in controller.js???//
PlacedCandidates
</a>
</div>
I am calling one modal popup function. Here is controller.js
$scope.placedcandidatespopup = function()
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$(".placedcandidates").modal("show");
}
I am calling modal by name "placedcandidates".
Here is the modal
<div class="modal right fade placedcandidates" id="myModal1"
tabindex="-1" role="dialog" aria-labelledby="myModalLabel2">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6" data-ng-
repeat="student in allusers">
<input id="{{student.studentId}}" type="checkbox" value="
{{student.studentId}}" data-ng-
checked="selection.indexOf(student.studentId) >-1"
data-ng-click="toggleSelection(student.studentId)"/>
<label for="{{student.studentId}}"></label>
{{student.firstName}}
</div>
</div>
</div>
<div class="modal-footer" style="position: fixed;">
<input type="button" value="Submit" class="btn" data-ng-
click="savePlacementStudents()">
</div>
</div>
</div>
</div>
After clicking on button popup modal will display with all Students with checkboxes placed beside them.Now I am able to save studentId into database.But I am not able to pass placementId for saving.
Here is my savePlacementStudents method in controller.js.
$scope.selectedStudents = {};
$scope.savePlacementStudents = function(selectedStudents)
{
selectedStudents.selectedList = $scope.selection;
AdminPlacementService.savePlacementStudents(selectedStudents).then
(function(response)
{
if(response.data=="success"){
$window.scrollTo(0,0);
$scope.selectedStudents = {};
$scope.getplacementdetails($scope.currentPageIndex);
$scope.successmessage="Student Selection Saved!;
$timeout(function() {
$scope.successmessage="";
$scope.closeplacedcandidatespopup();
}, 1500);
}
});
}
Can anyone tell how can I pass respective placementId to this saveStudents method() so that I can set that placementId for those students selected.
Here is the solution.
The placementId passed to function placedcandidatespopup can be saved as follows in function placedcandidatespopup
$scope.selectedPlacementId = placementId;
Now the same $scope will have access in Popup also as it is using same controller.js. And now you can use this $scope.selectedPlacementId anywhere in controller.js
So you don't need to pass placementId...!!
Hope that would help you..!!
$scope.placedcandidatespopup = function(id)
{
AdminUsersService.getAllUsers().then(function(response)
{
$scope.allusers=response.data;
console.log($scope.allusers);
})
$scope.inserted = {
placementId:id,
};
var modalInstance = $uibModal.open({
templateUrl: 'views/test/myModal1.html',
controller: 'TestCntrl',
size: "Modelwidth",
resolve: {
items: function () {
return $scope.inserted;
}
}
});
}
In model you have to access using items.placementId and when you savePlacementStudents() method send placementId as well with student info.
$scope.createPermission= function(form){
AppFactory.createNewPermission(form)
.success(function(data) {
$scope.updatedPermissions = data;
$scope.navMode='getPermission'
var original = $scope.permission;
$scope.reset(original);
$scope.permission = {}; // clear the form
})
.error(function(data) {
console.log('Error in creating permission: ' + data);
});
$scope.Execute=function(id) {
if($scope.navMode=='updatePermission') {
$scope.editPermission(id);
} else if($scope.navMode=='createPermission') {
$scope.createPermission($scope.permission);
}
}
}
$scope.reset= function(original) {
$scope.permission= angular.copy(original)
$scope.form2.$setPristine(true);
//$scope.form2.$setUntouched(true);
}
HTML:
<div class="row">
<div class="container col-sm-6 col-sm-offset-2"
ng-show="navMode == 'createPermission' || navMode=='updatePermission' || navMode=='getPermission'">
<div>
<h1>Permissions</h1>
</div>
</div>
<form class="form2" ng-show="showHide('Create')" ng-if=""name="form2" ng-submit="Execute(permissionId)" novalidate>
<div class="form-group" ng-class="{ 'has-success': form2.name.$valid && submitted, 'has-error': form2.name.$invalid && submitted }">
<label>Permission Name</label>
<input type="text" name="name" class="form-control" ng-model="permission.name" required/>
<p class="help-block" ng-show="form2.name.$error.required && submitted">
A permission name is required
</p>
</div>
<div class="row col-lg-offset-3">
<button class="btn btn-primary" ng-disabled="form2.$invalid" type="submit">Save</button>
</div>
</form>
</div>
I have above piece of code in controller and is executed on submission of the form. Now , It does work fine on page reload but I can not add data through form back to back. I need to reload teh page everytime to post new data through the form.
Why exactly is that ?
How do I fix this?
Without seeing the HTML part of this, I would guess you are using the action attribute of <form>. AngularJS provides ng-submit which allows you to set a handler for the submit event, without actually 'submitting' the form in the traditional sense. See https://docs.angularjs.org/api/ng/directive/ngSubmit.
I have an angular ui-grid in which data is displayed and in every row there is an "Edit" and "Delete" button. When the user clicks on the "Edit" then a modal window is displayed and the fields are populated and the user can edit the data. This is the user scenario I have. When the user clicks on the "Edit" button I pass through the id value and when angular creates the modal window I query the data from the server.
As you can see in the html the controller is not bound because it is managed by another controller. If it would be bound here then it would be called twice.
The fields are populated properly and when I change something in it and I want to save it then breeze says that nothing has changed in the entity and the log in the save method gives back the original values of the entity.
I assume something is wrong with the data binding but I don't know what.
According to the pluralsight video and breeze's documentation breeze tracks the changes in the entity.
What I'm doing wrong?
The form:
<form class="form-horizontal" name="editModuleModalForm">
<legend>Edit module</legend>
<div class="control-group">
<label class="control-label">Module name</label>
<div class="controls">
<input type="text"
placeholder="Module name here..."
data-ng-model="vm.sysmodule.name"
data-z-validate />
</div>
</div>
<div class="control-group">
<label class="control-label">Module Sort number</label>
<div class="controls">
<input type="text"
placeholder="Module sort number"
data-ng-model="vm.sysmodule.sortNo"
data-z-validate />
</div>
</div>
<div class="control-group">
<label class="control-label">Route</label>
<div class="controls">
<input type="text"
placeholder="Module route comes here..."
data-ng-model="vm.sysmodule.route"
value="vm.sysmodule.route"
data-z-validate />
</div>
</div>
<div class="control-group">
<button type="submit" class="btn btn-success" data-ng-click="vm.save()">Save</button>
<button type="submit" class="btn btn-danger" data-ng-click="vm.cancel()">Cancel</button>
</div>
</form>
Angular controller for the form
(function () {
'use strict';
var controllerId = 'editModuleController';
angular
.module('dilibApp')
.controller(controllerId, ['$scope', '$modalInstance', 'selectedModuleId', 'common', 'datacontext', editModuleController]);
function editModuleController($scope, $modalInstance, selectedModuleId, common, datacontext) {
/* jshint validthis:true */
var vm = this;
vm.title = 'editModule';
vm.sysmodule = undefined;
vm.cancel = cancel;
vm.save = save;
activate();
function activate() {
onDestroy();
common.activateController([getModulePropertiesToBeEdited()], controllerId);
}
function getModulePropertiesToBeEdited() {
return datacontext.sysmodule.getById(selectedModuleId)
.then(function (result) {
vm.sysmodule = result[0];
});
}
function onDestroy() {
$scope.$on('$destroy', function () {
datacontext.cancel();
});
}
function cancel() {
$modalInstance.dismiss('cancel');
}
function save() {
console.log(vm.sysmodule);
if (datacontext.hasChanges) {
datacontext.saveChanges();
console.log('Changes are saved!');
} else {
console.log('There are no changes to be saved!');
}
$modalInstance.close();
}
}
})();
Nothing is wrong with the binding. The root if the problem is that the datacontext doesn't have hasChanges method due to that the breeze's entityManager is wrapped in it. I had to rework the code a little bit, rethinking the responsibilities and it is working now.
What I'am trying to do is convert every user input into a label using angular. I believe that I'am doing the right thing, but is not working. I will appreciate if somebody take a look at this code. Thank you
here is a plunker
<div class="row" ng-controller="tagForm">
<div ng-click="addEntry()">
<div class="col-xs-12 col-sm-12 col-md-10 ">
<input type="text" placeholder="What are your area of expertise" ng-model="newEntry.name" class="form-control border" />
</div>
<div class="col-xs-12 col-md-2 center form-button">
<input type="button" value="Add" class="btn btn-orange btn-add" />
</div>
<div class="col-md-8 col-sm-offset-2" id="up">
<br />
<span class="label label-primary" ng-repeat="entry in entries">{{entry.name}}</span>
</div>
</div>
</div>
app.controller('tagForm', ['$scope', function($scope) {
return $scope.addEntry = function() {
$scope.entries.push($scope.newEntry);
return $scope.newEntry = {};
};
}]);
You have a few things wrong in your Plunk, but here's some stuff to start with:
You need to wire up a click event on your Add button. Right now, its not doing anything when you click it
Bind to an ng-model on the scope just using 'newEntry'. All you're typing is a name so thats all you need to save on the scope.
Loop over entries, printing out just 'entry' instead of 'entry.name'
And your controller should look like this (no need for the returns)
app.controller('tagForm', ['$scope', function($scope) {
$scope.entries = [];
$scope.addEntry = function() {
$scope.entries.push($scope.newEntry);
};
}]);
See this fiddle:
http://jsfiddle.net/smaye81/anrv2qms/1/