I don't think ngValue does what you think it does. It is meant for use with Options (in Selects) and for Radio Buttons. See docs here.
Short answer: The values in your $scope.$watch are false because you set $scope.model.multiple to false in the controller and a hidden input in a view doesn't get bound to the model as you hoped it would.
In your code I think you are trying to set model.multiple's value in your view for no reason, and in a way that is not possible.
It is my opinion that you should be setting the value to true in the controller. I don't see any reason why you would need it to be handled within a hidden input. You mention that it is coming "from the server", but the view is rendered by AngularJS - not some other server.
The purpose of the two-way binding on inputs is so that user edits will be reflected in your model. There doesn't appear to be any binding at all on hidden inputs since they are not user editable. Hidden inputs are meant for form submissions, and Angular doesn't do those. Forms serve a different purpose in Angular.
Check out this Plunk to see that hidden inputs don't impact the model. View:
<body ng-controller="MainCtrl">
<input type="hidden" ng-model="model.multiple" ng-value="true" value="true" />
<input type="hidden" ng-model="model.test" />Hidden inputs have no impact on the model.
<br>That's why this is blank: '{{model.test}}'
</body>
Controller:
app.controller('MainCtrl', function($scope) {
$scope.model = {
images: [],
multiple: false
}
$scope.$watch('model.multiple', function(newVal, oldVal) {
console.log('New: ' + newVal);
console.log('Old: ' + oldVal);
});
});