1. Answer to your first question:
When I type into the input box, I don't see it getting reflected in the {{x2}} output
This is because x1 or x2 are plain literals and in Javascript, literals are not passed by reference but objects are. So if you would have created an object to reference the value, it might have worked. For example:
var m = angular.module("m1", []);
m.controller('c', function($scope) {
$scope.x1 = {myModel: ''};
$scope.x2 = $scope.x1;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<div ng-app="m1" ng-controller='c'>
<input ng-model="x1.myModel">
<br>
<span>{{x2.myModel}}</span>
</div>
The above will work because x1 is an object and when you assign it to x2, it's reference is passed hence both are same. This was not the case when you were using x1 as the plain literal string.
The above will again not work when you clone or copy the object using angular.copy. See an example of the same:
var m = angular.module("m1", []);
m.controller('c', function($scope) {
$scope.x1 = {myModel: ''};
$scope.x2 = angular.copy($scope.x1);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<div ng-app="m1" ng-controller='c'>
<input ng-model="x1.myModel">
<br>
<span>{{x2.myModel}}</span>
</div>
This is because now you are not actually passing by reference but you are literally cloning the object. Now this is became same as your first problem. You are only copying the value from x1 to x2 at the time when your controller is initialized but not when your value in x1 is modified.
2. Answer to your second question:
But when I do it via a function, it works
When you used function, it worked because it is a feature of Angular that when you write a scope function in Angular and you use it in your view like {{x2()}} then Angular will auto update the view whenever the returned value from the function (x2() in this case) is changed/updated.
3. Solutions
There are multiple solutions to this problem that others have already mentioned.
3.1 Use $watch
(https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch)
var m = angular.module("m1", []);
m.controller("c", function($scope) {
$scope.$watch("x1", function(newValue) {
$scope.x2 = $scope.x1;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<div ng-app="m1" ng-controller='c'>
<input ng-model="x1">
<br>
<span>{{x2}}</span>
</div>
3.2 Use ng-change
(https://docs.angularjs.org/api/ng/directive/ngChange)
var m = angular.module("m1", []);
m.controller("c", function($scope) {
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<div ng-app="m1" ng-controller='c'>
<input ng-model="x1" ng-change="x2 = x1">
<br>
<span>{{x2}}</span>
</div>
In this way, you don't need any Javascript code.
3.3 Use objects
Use object instead of plain String literals like I mentioned above to avoid this problem.
3.4 Use a function
Use the function feature of Angular like you already mentioned in your question.