Angularjs model not update view when modified by child controller - angularjs

I have to update a parameter of the parent controller from a nested controller.
I'm able to read the parameter, but when I change it it does not update into the view (webpage)... help plz :)
This is my js:
app.controller('signalCtrl', [ '$scope', 'DB', function($scope, service) {
this.address = null;
}]);
app.controller('reportMap', ['$scope', function($scope) {
this.updateParent = function() {
$scope.$parent.tab.address = 'something';
}
}]);
And this is my HTML:
<div ng-controller="signalCtrl as signal">
<input type="text" ng-model="signal.address">
[...]
<div ng-controller="reportMap as map">
[...]
</div>
</div>

The address property in parent controller is not bound to $scope, but to this object, so you even can't reach that property that way. I suggest you to move your updating function to parent controller:
app.controller('signalCtrl', [ '$scope', 'DB', function($scope, service) {
var self = this;
self.address = null;
self.update = function(newValue) {
self.address = newValue;
}
}]);
app.controller('reportMap', ['$scope', function($scope) {
var self = this;
self.someValue = 'something';
}]);
HTML:
<div ng-controller="signalCtrl as signal">
<input type="text" ng-model="signal.address">
[...]
<div ng-controller="reportMap as map">
<button type="button" ng-click="signal.update(map.someValue)">Click!</button>
[...]
</div>
</div>
You don't call updating function in the presented code, so I added a button to show how to use it.

use signal instead of tab
app.controller('reportMap', ['$scope', function($scope) {
this.updateParent = function() {
$scope.$parent.signal.address = 'something';
}
}]);
see this link : https://plnkr.co/edit/RhQLfBy2heecJDuCcq9s?p=preview

Ok, probably the error is into te HTML:
(function () {
var app = angular.module('segnalazioni', ['filters', 'smart-table', 'smart-table-server']);
app.controller('nuovaSegnalazioneCtrl', [ '$scope', 'DB', function($scope, service) {
var self = this;
this.activatedTab = "tab_animale";
this.chipNumber = null;
this.indirizzo = 'ind';
this.setIndirizzo = function() {
self.indirizzo = "VIA ROMA";
console.log("AGGIORNAMENTO INDIRIZZO");
}
I call setIndirizzo from the child (i don't pass a value I know, but it is not the problem): into the console i read "AGGIORNAMENTO INDIRIZZO", but the value into the VIEW does not change...
this is a link to the complete html file.
https://www.dropbox.com/s/gzlm997ub8fot7r/html.txt?dl=0

Related

Passing Object from One Controller to Another AngularJS

I need to pass an object from one controller to another and have used this solution but it is not working.
Here the code:
angular.module("customerApp", [])
.controller('MainCtrl', function ($scope, myService, $http, $location) {
var vm = this;
vm.pinFormCheck = function () {
vm.count++;
if (vm.pinForm.$valid && vm.details.PIN === vm.pin && vm.count <= 2) {
location.href = "http://localhost:51701/Home/MainMenu";
$scope.obj = {
'cid': 'vm.details.CID',
'name': 'vm.details.Name',
'pin': 'vm.details.PIN',
'bal': 'vm.details.Bal',
'status': 'vm.details.cardStatus'
};
console.log(vm.details.Bal);//the correct balance get displayed in console
} else {
vm.failPin = true;
}
};
})
.controller('CheckCtrl', function ($scope, myService) {
$scope.data = myService.getObj();
})
.factory('myService', function () {
var obj = null;
return {
getObj: function () {
return obj;
},
setObj: function (value) {
obj = value;
}
}
});
Here is the view from which the first object is passed:
<body ng-app="customerApp">
<div ng-controller="MainCtrl as vm">
<form name="vm.pinForm">
<input type="password" ng-model="vm.pin" ng-required="true" />
<p><button ng-disabled="vm.count >=3" ng-click="vm.pinFormCheck();" ng-init="vm.count=0">Proceed</button></p>
</form>
...
Here' the second view where I need the object
<html ng-app="customerApp">
<body ng-controller="CheckCtrl">
<div>
<h1>your balance is {{data.bal}}</h1>
....
The balance from vm.details.Bal from the first view must appear in data.bal in the second view, but nothing is appearing.
You can just save vm.details in some factory.
And then get it in CheckCtrl from this factory.
Factories in AngularJS implement singleton pattern. So saved data will be kept in until your app exists.
You tried to do next thing myService.getObj(); But you didn't save anything to the service.
Inject myService to the MainCtrl and then save details into it.

Sharing scope data in controller

My spring mvc controller returns an object.
My scenario is:
On click of a button from one page say sample1.html load a new page say sample2.html in the form of a table.
In sample1.html with button1 and controller1--> after clicking button1-->I have the object(lets say I got it from backend) obtained in controller1.
But the same object should be used to display a table in sample2.html
How can we use this object which is in controller1 in sample2.html?
You can use a service to store the data, and inject it in your controllers. Then, when the value is updated, you can use a broadcast event to share it.
Here is a few example:
HTML view
<div ng-controller="ControllerOne">
CtrlOne <input ng-model="message">
<button ng-click="handleClick(message);">LOG</button>
</div>
<div ng-controller="ControllerTwo">
CtrlTwo <input ng-model="message">
</div>
Controllers
function ControllerOne($scope, sharedService) {
$scope.handleClick = function(msg) {
sharedService.prepForBroadcast(msg);
};
}
function ControllerTwo($scope, sharedService) {
$scope.$on('handleBroadcast', function() {
$scope.message = sharedService.message;
});
}
Service
myModule.factory('mySharedService', function($rootScope) {
var sharedService = {};
sharedService.message = '';
sharedService.prepForBroadcast = function(msg) {
this.message = msg;
this.broadcastItem();
};
sharedService.broadcastItem = function() {
$rootScope.$broadcast('handleBroadcast');
};
return sharedService;
});
JSFiddle demo
you can use factory to share data between controllers
<div ng-controller="CtrlOne">
<button ng-click="submit()">submit</button>
</div>
<div ng-controller="CtrlTwo">
{{obj}}
</div>
.controller('CtrlOne', function($scope, sampleFactory) {
$scope.sampleObj = {
'name': 'riz'
}; //object u get from the backend
$scope.submit = function() {
sampleFactory.setObj($scope.sampleObj);
}
})
.controller('CtrlTwo', function($scope, sampleFactory) {
$scope.obj = sampleFactory.getObj();
})
.factory('sampleFactory', function() {
var obj = {};
return {
setObj: function(_obj) {
obj = _obj;
},
getObj: function() {
return obj;
}
}
})

Using objects in child controller from parent controller in Angular

I have a Parent Angular Controller that has a method that needs to be shared with some other controller. The parent controller looks like this:
"use strict";
(function() {
var ParentCtrl = function($scope, atomico, Asset) {
var _this = this;
_this.busy = atomico.identity == null;
_this.oldestTimestamp = null;
_this.assets = [];
/**
* Infinite scrolling, fetches more assets when the user scrolls down.
*/
_this.fetch = function() {
if (_this.noMoreAssets) { return; }
_this.busy = true;
Asset.all(atomico.metadata['campaign'].id, _this.oldestTimestamp, $scope.dates.start, $scope.dates.end, function(assets) {
_this.busy = false;
if (assets.length > 0) {
_this.assets = _this.assets.concat(assets);
_this.oldestTimestamp = moment(assets[assets.length - 1].start).unix();
} else {
_this.noMoreAssets = true;
}
});
};
};
ParentCtrl.$inject = [ '$scope', 'atomico', 'Asset' ];
angular.module('myModule').controller('ParentCtrl', ParentCtrl);
})();
I am extending this controller in another one to have infinite scrolling to work in a view. This is the child controller:
"use strict";
(function() {
var ChildCtrl = function(atomico, userState, $controller, $scope) {
var _this = this;
angular.extend(_this, $controller('ParentCtrl', {$scope: $scope}));
// Fetch assets after user, campaign and account data is available.
atomico.ready(function(){
var dates = userState.getCampaignViewData(atomico.metadata['campaign'].id).list_view;
$scope.dates = _.isEmpty(dates) ? {start: moment(), end: moment()} : dates;
_this.busy = false;
});
};
CampaignListCtrl.$inject = [ 'atomico', 'userState', '$controller', '$scope' ];
angular.module('myModule').controller('ChildCtrl', ChildCtrl);
})();
And in my view i have this:
<div id='agenda_viewer' ng-controller="ChildCtrl as ctrl">
<p class="at-text-center at-block-center c-empty-list" ng-hide='ctrl.assets.length || ctrl.busy'>
There are no assets to show for this day
</p>
<div class="agenda-flight__content at-row" infinite-scroll='ctrl.fetch()' infinite-scroll-disabled='ctrl.busy' infinite-scroll-parent="true">
<div class="agenda-flight at-row agenda-asset__live" ng-repeat='asset in ctrl.assets' ng-init='asset.collapsed = false'>
<directive-list-row asset='asset'></directive-list-row>
<directive-list-expanded asset='asset' ng-if='asset.collapsed'></directive-list-expanded>
</div>
</div>
<div class='c-loading' ng-show='ctrl.busy'>Loading data...</div>
</div>
The problem i am having is that the ctrl.assets is always empty even thought the service returns the data. Is this an issues with ctrl.assets being defined in the parent controller and not visible in the child controller? How can i make that assets object shared to the child controller so i can see the data in the UI?
What I ended up doing is moving some of this controller variables into the $scope and now seems to be working good. $scope is being shared across children

Factory value not updated in model ...what I am doing wrong?

I am new to angular-js. I have two controllers (welcomeContoller,productController) and both handling the same model within the factory.
When the model getting updating by one controller(productController) it should reflect the update in another controller. (welcomeContoller)
But its not happening now.
HTML code :
<body ng-app="myApp">
<div ng-controller="welcomeContoller">
{{totalProductCnt}}
</div>
<div ng-controller="productController">
<div class="addRemoveCart">
<span class="pull-left glyphicon glyphicon-minus" ng-click="removeProduct()"></span>
<span class="pull-right glyphicon glyphicon-plus" ng-click="addProduct(1)"></span>
</div>
</div>
JS code
var myApp = angular.module("myApp", ['ui.bootstrap']);
myApp.factory("productCountFactory", function() {
return {
totalProducts:0
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory)
{
$scope.totalProductCnt = productCountFactory.totalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.totalProducts++;
alert(productCountFactory.totalProducts);
};
$scope.removeProduct = function() {
if(productCountFactory.totalProducts >=1)
productCountFactory.totalProducts--;
alert(productCountFactory.totalProducts);
};
});
Even after the addProduct is called the totalProductCnt is displaying as zero. I want to display the value for each increment.
Plunkr Link
Put the factory object reference on scope:
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.productCountFactory = productCountFactory;
});
Watch the property of the object.
{{productCountFactory.totalProducts}}
The DEMO on PLNKR.
By putting a reference on scope, on every digest cycle the watcher looks up the value of the property and updates the DOM if there is a change.
The totalProductCnt from your welcomeController isn't updated because it is assigned only once when the controller is created.
You can use several solutions to refresh the displayed value. Use a getter for your totalProducts in the factory :
myApp.factory("productCountFactory", function() {
var totalProducts = 0;
return {
getTotalProducts: function() {
return totalProducts;
},
addProduct: function() {
totalProducts++;
},
removeProduct: function() {
totalProducts--;
}
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.getTotalProducts = productCountFactory.getTotalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.addProduct();
};
$scope.removeProduct = function() {
if (productCountFactory.getTotalProducts() >= 1)
productCountFactory.removeProduct();
};
});
And update the view accordingly:
<div ng-controller="welcomeContoller">
{{getTotalProducts()}}
</div>
Plunkr Link

Using 'controller as' syntax to pass object values to parent controller

When using the $scope controller syntax, it's simple to set a value on a parent controller's object. For example
<div ng-controller="ParentController">
{{myValue.a}}
<div ng-controller="ChildController">
{{myValue.a}}
</div>
</div>
app.controller('ParentController', function($scope) {
$scope.myValue = {};
$scope.myValue.a = 1;
});
app.controller('ChildController', function($scope) {
$scope.myValue.a = 2;
});
The above outputs:
2
2
Is there a way to achieve the same functionality with the controller as syntax without referencing $scope in the child controller?
You could do it using a service, or you could do it referencing the scope.
The behavior that you are using, scope inheritance, is often referred to as an unwanted side affect. This is why isolated scopes are used with the controllerAs syntax.
In the following example you can see we achieve the same result using sharing the myValue property on the $scope along with the controllerAs syntax.
angular.module('app', [])
.controller('ParentController', ParentController)
.controller('ChildController', ChildController);
ParentController.$inject = ['$scope'];
function ParentController($scope) {
this.myValue = {};
this.myValue.a = 1;
$scope.myValue = this.myValue;
}
ChildController.$inject = ['$scope'];
function ChildController($scope) {
this.myValue = $scope.myValue;
this.myValue.a = 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<div ng-controller="ParentController as parent">
parent: {{parent.myValue.a}}
<div ng-controller="ChildController as child">
child: {{child.myValue.a}}
</div>
</div>
</div>
This can be accomplished without $scope using a service:
angular.module('app', [])
.controller('ParentController', ParentController)
.controller('ChildController', ChildController)
.service('valueService', ValueService);
ParentController.$inject = ['valueService'];
function ParentController(valueService) {
this.myValue = {};
this.myValue.a = 1;
valueService.setValue(this.myValue);
}
ChildController.$inject = ['valueService'];
function ChildController(valueService) {
this.myValue = valueService.getValue();
this.myValue.a = 2;
}
function ValueService() {
var storedValue;
this.getValue = function() {
return storedValue;
}
this.setValue = function(value) {
storedValue = value;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<div ng-controller="ParentController as parent">
parent: {{parent.myValue.a}}
<div ng-controller="ChildController as child">
child: {{child.myValue.a}}
</div>
</div>
</div>
if you don't like to use $scope you may pass outer controller downstream, see directives communication
No, it's not possible from within ChildController.
Don't think of ControllerAs as a newer style of $scope. Each has a different use.
ControllerAs does not publish values onto scope (it actually does - via the alias, but the alias should not be assumed to be known to a child Controller since the alias is defined in the View).
I use both where needed and I use the following convention:
app.controller("ParentCtrl", function($scope){
// $scope-inherited view model
var VM = $scope.VM = ($scope.VM || {});
// controller-specific view model
var vm = this;
VM.valueVisibleToChildControllers = "foo";
vm.valueVisibleOnlyToTheView = "bar";
});

Resources