Angular $apply does not update the view - javascript

I have a form, when I submit it, it pushes some object to my array. Beneath that form I have a table that shows all items in that array. I want my table to update automatically (without refreshing the page) when new item pushed.
Submit button:
<button type="submit" class="btn btn-default" ng-click="updateTable()">Pay</button>
In my controller:
$scope.updateTable = function() {
setTimeout(function () {
$scope.$apply();
$scope.$digest();
}, 0);
};
However, it does not work.
I tried different approaches like $watch service, but i`ve got the same result.
Table
<div class="row paytable">
<div class="col-xs-10 col-xs-offset-1">
{{payments.length}}
<table class="table table-hover ">
<tr>
<td>Id</td>
<td>Amount</td>
<td>Cause</td>
</tr>
<tr ng-repeat="item in payments">
<td>{{item.id}}</td>
<td>{{item.amount}}</td>
<td>{{item.cause}}</td>
</tr>
</table>
</div>
</div>
Controller
app.controller('mainController', [ 'user', '$rootScope', '$scope', 'payment', '$timeout', function(user, $rootScope, $scope, payment, $timeout) {
user.getUsers();
user.newUser();
$rootScope.currentUser = user.currentUser();
$scope.payments = payment.getPayments();
$scope.newPayment = payment.newPayment;
$scope.updateTable = function() {
setTimeout(function () {
console.log('apply ------------');
$scope.$apply();
$scope.$digest();
}, 0);
};
$scope.showPayMessage = function() {
console.log('im here');
$scope.showSM = true;
$timeout(function() {
$scope.showSM = false;
}, 2000);
};
}]);
payment - my service for array manipulation.
Form
<div class="newpay row" >
<div class=" col-xs-10 col-xs-offset-1">
<h1>Hello, {{currentUser.name}}</h1>
<h4 ng-show="showSM" class="bg-success">Payment confirmed</h4>
<form name="inputform" ng-submit="newPayment(amount, cause); showPayMessage();">
<div class="form-group">
<label for="exampleInputEmail1">Amount</label>
<input type="number" name="amount" ng-model="amount" class="form-control" id="exampleInputEmail1" placeholder="Amount" required>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Cause</label>
<input type="text" name="cause" ng-model="cause" class="form-control" id="exampleInputPassword1" placeholder="Cause" required>
</div>
<button type="submit" class="btn btn-default" ng-click="updateTable()">Pay</button>
</form>
</div>
</div>
payments: {{payments.length}}
<payments-table payments="payments"></payments-table>
To display that table I created directive.

$scope.$apply and $scope.$digest are better suited for working with 3rd party libraries or testing. In your case Angular is well aware to your changes. The thing is, your payments array, that resides in a service should be queried again after submitting a new item (unless you have a direct reference to the array, then no query should be made).
Like this:
View
<form name="inputform" ng-submit="onSubmit()">
Controller
$scope.onSubmit = function() {
newPayment($scope.newItemAmount, $scope.newItemCause); // Assuming they are properties in the controller
showPayMessage();
$scope.payments = payment.getPayments(); // getting the updated array
}

Related

Invoke Angularjs controller method from Angularjs view which related to another Angularjs controller

I am new to Angularjs, I have created simple web application that takes the details from user and display the details in the view. I am facing problem while invoking a method of one controller from another angular view. Can anyone help me, Thanks.
home.html
<div id="main">
<div id="first">
<form ng-controller="homeController as model" ng-submit="push();">
<h1>Vehicle Form</h1>
<h4>Please fill all entries.</h4>
<br>
<label>Model :</label>
<input name="dname" placeholder="Enter Model" type="text" ng-model="model.user.model">
<br>
<label>Name :</label>
<input name="demail" placeholder="Enter name" type="text" ng-model="model.user.name">
<br>
<label>Color :</label>
<input name="demail" placeholder="Enter color" type="text" ng-model="model.user.color">
<br>
<label>Price :</label>
<input name="demail" placeholder="Your Email" type="text"ng- model="model.user.price">
<br>
<input name="dsubmit" type="submit" value="Send">
</form>
</div>
</div>
<br>
<br>
<h1>Vehicle Table </h1>
<table class="table table-striped table-hover table-users" ng-controller="homeController">
<thead>
<tr>
<th>Id</th>
<th>Model</th>
<th>Name</th>
<th>Color</th>
<th>Price</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="vehicle in hello">
<td>{{vehicle.id}}</td>
<td>{{vehicle.model}}</td>
<td>{{vehicle.name}}</td>
<td>{{vehicle.color}}</td>
<td>{{vehicle.price}}</td>
<td><a class="btn mini blue-stripe" ui-sref="about" ng-click="setValue(vehicle.id)">Edit</a></td>
<td>Delete</td>
</tr>
</tbody>
</table>
home.js (controller file)
var myapp = angular.module('demo').controller("homeController", function($scope,myService){
myService.async().then(function(d){
$scope.hello=d.data;
});
var model=this;
model.user={
id:"",
model:"",
name:"",
color:"",
price:""
};
$scope.push = function(){
myService.saveUser(model.user);
model.user='';
}
});
about.html
<div id="main">
<div id="first">
<form ng-controller="aboutController" ng-submit="addValue();">
<h1>Vehicle Edit Form</h1>
<br>
<label>Id :</label>
<input name="id" placeholder="Enter Id" type="text" ng-model="id" value="value.id">
<br>
<label>Model :</label>
<input name="model" placeholder="Enter Model" type="text" ng-model="model" value="value.model">
<br>
<label>Name :</label>
<input name="name" placeholder="Enter name" type="text" ng-model="name" value="value.name">
<br>
<label>Color :</label>
<input name="color" placeholder="Enter color" type="text" ng-model="color" value="value.color">
<br>
<label>Price :</label>
<input name="price" placeholder="Your Email" type="text" ng-model="price" value="value.price">
<br>
<input name="update" type="Update" value="Send">
</form>
</div>
</div>
about.js (second controller)
angular.module('demo').controller("aboutController", function($scope, aboutService) {
$scope.value;
$scope.setValue = function() {
aboutService.getVehicle().success(function (response) {
$scope.value = studs.data;
})
};
$scope.addValue = function () {
var stud = {
id:"$scope.id",
model:"$scope.model",
name:"$scope.name",
color:"$scope.color",
price:"$scope.price"
};
aboutService.setVehicle(stud).
success( function (){
concole.log("hello");
})
};
});
rest.js(module file)
var myapp = angular
.module('demo', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'Views/home.html',
controller: 'homeController'
})
.state('about', {
url: '/about',
templateUrl: 'Views/about.html',
controller: 'aboutController'
})
.state('contact', {
url: '/contact',
templateUrl: 'Views/contact.html',
controller: 'contactController'
});
});
homeService.js
myapp.factory('myService',function($http){
var myService={
async : function(){
var promise= $http.get('http://192.168.50.127:8080/SpringRestfulVehicleDemo2/vehicle/all').then(function(response){
return response;
});
return promise;
},
saveUser : function(userArray){
$http.post('http://192.168.50.127:8080/SpringRestfulVehicleDemo2/vehicle/add ',userArray).success(
function(userArray,status,headers,config){
});
}
};
return myService;
});
aboutService.js (another service file)
myapp.factory('aboutService',function($http){
var aboutService={};
var urlBase='http://192.168.50.127:8080/SpringRestfulVehicleDemo2/vehicle/';
aboutService.getVehicle = function () {
retun $http.get(urlBase+'/byId/:id');
};
aboutService.setVehicle= function (){
return $http.post(urlBase+'/update/:id');
}
return aboutService;
});
What I am doing is getting data from server and displaying data in a table. I want to edit the selected row in another view. I facing an issue when I click edit button in home.html. It should invoke about.js (controller) setValue() method.
To do this, you need your controllers to communicate to each other. Communication can happen using any of the following methods
Use $emit + $on / $broadcast + $on
Make a service which contains that function and is injected to the controllers which want to communicate with each other.
In your case either you can move the setValue method to a shared service between the controllers using it or you can use method 1.
You already know how to make a service. For method 1 example is given below:
app.controller('One', ['$scope', '$rootScope'
function($scope) {
$rootScope.$on("CallParentMethod", function(){
$scope.parentmethod();
});
$scope.parentmethod = function() {
// task
}
}
]);
app.controller('two', ['$scope', '$rootScope'
function($scope) {
$scope.childmethod = function() {
$rootScope.$emit("CallParentMethod", {});
}
}
]);

Angular $scope not passing results to parent controller on update

In my App I have an $http.get() request that stores data into the array $scope.requirements and a boolean into $scope.requirementsFulfilled.
I have a directive using the same controller as the page. They both do an ng-repeat on the $scope.requirements. When the requirementsFulfilled is false only the directive version shows, when true only the containing page.
The problem is when I envoke $http.get() after the first time the results are only being stored in the directive version. How do I make sure this information is bound to both?
Within the controller...
$scope.requirementsFulfilled;
$scope.requirements = [];
$scope.getRequirements = function(url) {
$http.get(url)
.then(function(res){
$scope.requirements = res.data.requirements;
$scope.setFulfilled( res.data.fulfilled );
});
};
$scope.submitRequirementScan = function() {
if ($scope.checkRequirement() ) {
$scope.getRequirements('tempjson/requiredPartsFulfilled.json');
}
};
$scope.setFulfilled = function( inputFulfilled ) {
$scope.requirementsFulfilled = inputFulfilled;
};
$scope.getRequirements('tempjson/requiredParts.json');
The page gets the requirements and populates the page. Then the user takes actions which fires off checkRequirement() and then fetches the new json if true. From this point only the directive is updating.
I believe that a child scope is being created for the directive, but I am not certain exactly what is happening. Here is the entirity of the directive info.
.directive("operationRequirements", function () {
return {
restrict: "E",
templateUrl: "requirements/requirements.html"
};
});
What is going on with it?
edit - Html for the directive
<div class="col-md-6 col-md-offset-3">
<h5>Scan Requirements</h5>
<form ng-submit="submitRequirementScan()" ng-controller="operationCtrl">
<label> <div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<input type="text" ng-model="text" name="text" placeholder="Scan Barcode" autofocus /></label>
<input type="submit" id="submit" value="Submit Scan" class="btn" />
<table class="table table-hover">
<tr ng-repeat="requirement in requirements | filter : unScannedFilter">
<td>{{$index + 1 }}</td>
<td>
<div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<div class="glyphicon glyphicon-check ng-show" ng-show="requirement.scanned"></div>{{requirement.scanned}}
<div class="col-md-4">
<input type="checkbox" ng-model="requirement.scanned">
</div>
</td>
<td>{{requirement.partId}} - {{requirement.partDescription}}</td>
</tr>
</table>
</form>
</div>
edit 2 -- Html that invokes the directive operation-Requirements and the on page display of the requirements hidden with ng-show.
<div class="row" ng-hide="requirementsFulfilled" >
<operation-Requirements></operation-Requirements>
</div>
<div class="col-md-12" ng-show="requirementsFulfilled">
<table class="table table-hover">
<tr ng-repeat="requirement in requirements">
<td>{{$index + 1 }}</td>
<td>
<div class="glyphicon glyphicon-barcode ng-hide" ng-hide="requirement.scanned"></div>
<div class="glyphicon glyphicon-check ng-show" ng-show="requirement.scanned"></div>
</td>
<td>{{requirement.partId}} - {{requirement.partDescription}}</td>
</tr>
</table>
</div>
So maybe this will help point you in the right direction. What I've done is pulled out the requirements stuff into its own service. Now you have a singleton that handles everything that deals with parts. When its updated in one place its updated everywhere. The directive no longer needs that other controller.
http://plnkr.co/edit/Nej79OI3NrKcrkMNix3D?p=preview
app.service('partsService', function() {
return {
requirementsFulfilled: false,
requirements: [],
getRequirements: function () {
this.requirements.push({partId: 1, partDescription: 'Some Desc', scanned: false});
this.requirements.push({partId: 2, partDescription: 'Some Desc 2', scanned: true});
},
submitScan: function (id) {
this.requirements.filter(function (part) {
return part.partId === id;
}).map(function (part) {
part.scanned = true;
});
this.requirementsFulfilled = this.requirements.filter(function (part) { return !part.scanned }).length === 0;
}
};
});

AngularJS: pass perameter to $location.path

I suspect what I'm trying to do is very simple, I'm new to Angular so some obvious practices sort of go over my head. I'm having trouble accessing the show view (sorry, I'm coming to angular from Rails, so I still think in those terms a little bit) for my Acts resource. The view renders fine, but it isn't displaying the data I would like. I suspect the template isn't receiving the $scope.act variable I'm defining in the controller. When I use console.log in the controller, I can see that the variable contains all the data I want to use. I assume I have to do something to pass the variable as a parameter to the template, but I'm not sure how I'd do that.
Here's my code:
app.js
$(document).on('page:load', function() {
return $('[ng-app]').each(function() {
var module;
module = $(this).attr('ng-app');
return angular.bootstrap(this, [module]);
});
});
var snowball_effect = angular.module('snowball_effect', [
'templates',
'ngRoute',
'ngResource',
'controllers'
]);
snowball_effect.config([
'$routeProvider', function($routeProvider) {
return $routeProvider
.when('/', {
templateUrl: "static_pages/templates/index.html",
controller: 'StaticPagesController'
})
.when('/acts/index', {
templateUrl: "acts/templates/index.html",
controller: 'ActsController'
})
.when('/acts/:id', {
templateUrl: "acts/templates/show.html",
controller: 'ActsController'
});
}
]);
var controllers = angular.module('controllers', []);
ActsController.js
controllers = angular.module('controllers');
controllers.controller('ActsController', [
'$scope',
'$routeParams',
'$location',
'$resource',
function($scope,$routeParams,$location,$resource) {
var Act = $resource('/acts/:actId', {
actId: "#id",
format: 'json'
}, {
'create': {
method: 'POST'
}
});
$scope.acts = Act.query();
$scope.addAct = function() {
act = Act.save($scope.newAct, function() {
$scope.acts.push(act);
$scope.newAct = '';
});
}
$scope.deleteAct = function(act) {
Act.delete(act);
$scope.acts.splice($scope.acts.indexOf(act), 1);
}
$scope.linkToShowAct = function(act) {
$scope.act = act;
console.log($scope.act);
$location.path('acts/' + act.id);
}
}]);
show.html
<div class="acts-show">
<div class="container" ng-controller="ActsController">
<div class="body">
<h1>
{{act.name}}
</h1>
<p class="act-show-description">
{{act.description}}
</p>
<p class="act-show-inspires">
<strong>Inspires:</strong>
{{act.inspires}}
</p>
Edit
Back
</div>
</div>
</div>
index.html
<div class="actions_body">
<div class="container">
<h2>Listing Actions</h2>
<div ng-controller="ActsController" class="body">
<table class="row">
<thead>
<tr>
<th class="col-md-2 col-md-offset-1 active">
<label>Name</label>
</th>
<th class="col-md-4">Description</th>
<th class="col-md-2">Inspires</th>
<th colspan="2" class="col-md-2">Modify</th>
</tr>
</thead>
<tbody ng-repeat="act in acts">
<td class="col-md-offset-1 col-md-2">{{act.name}}</td>
<td class="col-md-4">{{act.description}}</td>
<td class="col-md-2">{{act.inspires}}</td>
<td>Edit</td>
<td><button ng-click="deleteAct(act)">Delete</a></button>
</tbody>
</table>
<br>
<button ng-click="newActShow=true">New Action</button>
<button ng-click="newActShow=false">Hide</button>
<div ng-show="newActShow" id="newAct">
<div class="row">
<form class="form-inline" ng-submit="addAct()">
<div class="col-md-3 form-group">
<label for="newActname">Name</label>
<input type="text" ng-model="newAct.name" id="newActname" placeholder="Name" class="form-control col-md-2">
</div>
<div class="col-md-3 form-group">
<label for="newActdescription">Description</label>
<input type="textarea" ng-model="newAct.description" id="newActdescription" placeholder="Description" class="form-control col-md-2">
</div>
<div class="col-md-3 form-group">
<label for="newActinspires">Inspires</label>
<input type="number" ng-model="newAct.inspires" id="newActinspires" placeholder="Inspires" class="form-control col-md-2">
</div>
<div class="col-md-3 form-group">
<input type="submit" value="+" class="btn btn-success">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
try $locationChangeStart in order to make sure your value is set to the scope variable before the state actually changes and the route happens, even if you put the $location.path('acts/' + act.id); before setting the variable, there is no guarantee that the value will be set before the state change (the actual routing).
I would prefer (a more safe value setting method) using a promise for example ..

Can't access form inside AngularJS controller

Can't access form variable from my controller, when i try to access it by $scope.locationForm i've got 'undefined', but when i call console.log($scope) i can see in console there have loactionForm.
My HTML code
<div ng-controller="LocationsController as ctrl">
<form class="form-inline" name="locationForm">
<div class="form-group">
<!-- <div class="input-group"> -->
<label for="location-name">Название населенного пункта</label>
<input required
name="name"
ng-model="ctrl.location.name" type="text" class="form-control" id="location-name" placeholder="Название населенного пункта">
<label for="location-name">Район</label>
<select required
name="region_id"
ng-model="ctrl.location.region_id"
ng-options="region.id as region.name for region in ctrl.regions" class="form-control" placeholder="Название района"></select>
<input ng-click="ctrl.save()"
ng-disabled="locationForm.$invalid" type="submit" class="btn btn-default" value="Cохранить">
<a class="btn btn-default" ng-click="ctrl.reset()" ng-show="locationForm.$dirty">Сброс</a>
<!-- </div> -->
</div>
</form>
My Controller code:
function LocationsController($scope, Location, Region, $q) {
var lc = this,
l_index;
lc.form ={};
lc.regions = lc.locations = [];
lc.regions = Region.query();
lc.regions.$promise.then(function(data) {
lc.locations = Location.query();
});
lc.getRegion = function (id) {
return lc.regions.filter(function(obj) {
return obj.id == id;
})[0].name;
};
console.log($scope);
// console.log($scope.locationForm);
lc.reset = function () {
lc.location = new Location;
}
lc.reset();
};
The problem is when the LocationsController is initialized the form element is not yet compiled. So one possible hack is to use a timeout like
function LocationsController($scope, Location, Region, $q, $timeout) {
//then later
$timeout(function(){lc.reset();})
}

getting data back to controller from form

I have this form below. When I change the text fields, it shows the changes here
<div>
{{authform.email}}{{authform.password}}
</div>
but when I try to submit the form by ng-click="signup()" on a button, it doesn't send me the value of text fields.
below is my code
<div class="col-md-12" ng-controller="authCtrl">
<div class="row">
<div class="col-md-14">
<div class="jumbotron">
<form>
<div class="createUserDiv"><input type="text" name="email" placeholder="enter your email address" ng-model="authform.email"/></div>
<div class="createUserDiv"><input type="text" name="password" placeholder="enter your password" ng-model="authform.password"/></div>
<div class="createUserDiv"><input type="text" name="confirmpassword" placeholder="confirm your password" ng-model="authform.confirmpassword"/></div>
<p><a class="btn btn-lg btn-success" ng-click="signup()">Splendid!<span
class="glyphicon glyphicon-ok"></span></a></p>
</form>
<div>
{{authform.email}} {{authform.password}}
</div>
</div>
</div>
</div>
</div>
here is my js
angular.module('myAPP')
.controller('authCtrl', function ($scope, $http, $location) {
$scope.signup = function() {
$scope.authform = {};
$scope.authform.email = "";
$scope.authform.password = "";
$scope.authform.confirmpassword = "";
var data = {
"dataBlob": {
"email": $scope.authform.email,
"password": $scope.authform.confirmpassword
}
};
console.log($scope.authform.email);
});
my console.log is coming up empty ...null....I am not sure why is it not binding the fields to data. I am pretty new to angular so I am still trying to figure out these things.
Stat your controller like this:
angular.module('myAPP')
.controller('authCtrl', function ($scope, $http, $location) {
$scope.authForm = {};
Then change your signup method to do this:
$scope.signup = function() {
console.log($scope.authForm);
}
Your values are already bound, but when you called $scope.authForm = {}; inside of signup, you are overwriting all of your values.
Also instead of ng-click="signup()" on your button, do this:
<form ng-submit="signup()">
Which will allow you to implement validations and submit on [enter] keypress when the user in an input field
For an example, see this fiddle

Categories