Reputation: 427
So I have a parent component that has a ton of smaller components inside of it. The general idea is that I need one component to take in the data in an input and display it on another component. This is what I have which doesn't quite work, more details on the problem afterwards:
const app = angular.module('app', []);
app.service('dataService', function() {
let data = {
key1: "",
key2: "",
key3: {
key4: 0,
key5: 0
}
}
this.getKey1 = function() {
return data.key1;
}
this.updateKey1 = function(str) {
data.key1 = str;
}
}
app.component('display', {
controller: displayController,
template: '<p>{{ keyOne }}</p>'
});
app.component('input', {
controller: inputController,
template: '<input ng-model="$ctrl.key1" ng-change="sendKey1()">'
}
function displayController($scope, dataService) {
const vm = this;
const self = $scope;
vm.$onInit = onInit;
function onInit() {
self.keyOne = dataService.getKey1();
}
}
function inputController($scope, dataService) {
const vm = this;
const self = $scope;
vm.$onInit = onInit;
function onInit() {
self.sendKey1 = function() {
dataService.updateKey1(vm.key1)
}
}
So the update works, but then it doesn't pass it to the display component. If I log the data object after updating it it's correct but it doesn't show up on the view.
Upvotes: 0
Views: 1273
Reputation: 2007
Take a look at A Tale of Frankenstein and Binding to Service Values in Angular.js.
Here's the quick summary of what is happening:
displayController
executes self.keyOne = dataService.getKey1()
. This assigns an empty string to $scope.keyOne
.{{ keyOne }}
watches $scope.keyOne
for changes. It initially evaluates to ""
, so an empty string is present in the view.inputController
changes dataService.data.keyOne
to some value, such as hello world
.{{ keyOne }}
once again evaluates $scope.keyOne
for changes as part of the digest cycle. Problem: $scope.keyOne
is still an empty string! displayController
doesn't know to fetch the latest value from dataService.data.keyOne
.Luckily, the fix is simple. You just need to get a reference to the data
object so that you can correctly evaluate data.keyOne
when watching for changes:
app.service('dataService', function() {
let data = {
key1: ""
}
//Expose the data object
this.getData = function() {
return data;
}
}
app.component('display', {
controller: displayController,
//Evaluate the current value of keyOne in the data object
template: '<p>{{ data.keyOne }}</p>'
});
function displayController($scope, dataService) {
const vm = this;
const self = $scope;
vm.$onInit = onInit;
function onInit() {
//Get a static reference to the data object.
//The data object itself shouldn't change, but its properties will.
self.data = dataService.getData();
}
}
Upvotes: 1
Reputation: 401
You are updating a string
data.key1 = str;
in the
let data = {
key1: "",
key2: "",
key3: {
key4: 0,
key5: 0
}
}
Angular doesn't bind strings between components, only binds objects.
see here https://plnkr.co/edit/wfwyyGpcMKOSHGFdg2DS?p=preview
var app = angular.module('plunker', ['ngRoute', 'ngAnimate', 'ngSanitize']);
app.service('dataService', function() {
let data = {
key1: "",
key2: "",
key3: {
key4: 0,
key5: 0
}
}
this.getData = function() {
return data;
}
this.updateKey1 = function(str) {
data.key1 = str;
}
});
app.component('inputc', {
controller: inputController,
template: '<input ng-model="$ctrl.key1" ng-change="sendKey1()">'
});
app.component('display', {
controller: displayController,
template: '<p>{{ data.key1 }}</p>'
});
function displayController($scope, dataService) {
const vm = this;
const self = $scope;
vm.$onInit = onInit;
function onInit() {
self.data = dataService.getData();
}
}
function inputController($scope, dataService) {
const vm = this;
const self = $scope;
vm.$onInit = onInit;
function onInit() {
self.sendKey1 = function() {
dataService.updateKey1(vm.key1)
}
}
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link href="style.css" rel="stylesheet" />
<script src="https://code.angularjs.org/1.6.2/angular.js"></script>
<!-- By setting the version to snapshot (available for all modules), you can test with the latest master version -->
<!--<script src="https://code.angularjs.org/snapshot/angular.js"></script>-->
<script src="https://code.angularjs.org/1.6.2/angular-route.js"></script>
<script src="https://code.angularjs.org/1.6.2/angular-animate.js"></script>
<script src="https://code.angularjs.org/1.6.2/angular-sanitize.js"></script>
<script src="app.js"></script>
</head>
<body>
<inputc></inputc>
<display></display>
</body>
</html>
Upvotes: 2