Angular - binding a dynamically created object - angularjs

I'm using Angular and I can't edit a dynamically created object, even though it is presented correctly (meaning the binding works).
I have the following view:
<html>
<head>
</head>
<body ng-app='TestApp'>
<div ng-controller='TestCtrl'>
<input ng-model="newModel().name"/>
</div>
</body>
</html>
And the following controller implementation:
var TestApp = angular.module("TestApp", []);
function TestCtrl($scope) {
$scope.newModel = function(){
return { name: 'Fresh' }
}
}
I'm using a method to return the correct object for binding because I need to execute some logic to decide which object should be binded.
The input field displays the correct, dynamically created, value. But I cant seem to edit it.
What am I doing wrong? Is this the wrong way to achieve such a functionality?
Thanks.

Instead of returning an object and by attaching a function to the scope, you can update a scope variable in the function.
Controller code:
var TestApp = angular.module("TestApp", []);
function TestCtrl($scope) {
$scope.newModel = {}; // initialize the scope variable
function updateScope () {
// do some logic
$scope.newModel = { name: 'Fresh' }; // update it with the required object
}
updateScope(); // run the function
}
HTML code:
<body ng-app='TestApp'>
<div ng-controller='TestCtrl'>
<!-- remove `()` since `newModel` is no longer a function -->
<input ng-model="newModel.name"/>
</div>
</body>
Hope this solves the issue.

Related

Passing data via service not updating second controller

I am trying to use service in AngularJS and pass data from one controller to another on click of a button.
I tried and can see that service value is updated but I am unable to retrieve in the second controller, however, I can retrieve in the first Controller.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<p>Search:<input type="text" ng-model="newValue"></p>
<button ng-click="myFunc(newValue)">OK</button>
</div>
<div ng-controller="myCtrl2">
{{receivedVal}}
</div>
<script>
var app= angular.module('myApp', []);
app.controller('myCtrl', function($scope,sharedProperties) {
$scope.stringValue = sharedProperties.getString();
$scope.myFunc = function(newValue) {
sharedProperties.setString(newValue);
$scope.stringValue = sharedProperties.getString();
console.log($scope.stringValue);
//I am getting the value here by calling sharedProperties.getString();
};
});
app.controller('myCtrl2', function($scope,sharedProperties) {
$scope.receivedVal = sharedProperties.getString();
console.log($scope.receivedVal);
//But I am not getting the updated value here by calling sharedProperties.getString();
});
app.service('sharedProperties', function() {
var stringValue = 'firstoccurence';
return {
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
},
}
});
</script>
</body>
</html>
receivedVal is always coming blank even service is getting updated.
By looking at your HTML code; I can see both the controllers have already been instantiated.
So when you do $scope.receivedVal = sharedProperties.getString(); in controller 2, you are just getting value from service one time only (Note : You are not continuously observing the value from service). And hence in template of controller 2 the default value firstoccurence shall be displayed.
You are actually updating the value on click of OK button, which in turns updates value in service. But there is no way you told angular that now as values has been changed then now controller 2 should get this new value.
To active the scenario that you want , you need to use $broadcast and $on so that you can continuously observe change happening in controller 1.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<p>Search:<input type="text" ng-model="newValue"></p>
<button ng-click="myFunc(newValue)">OK</button>
</div>
<div ng-controller="myCtrl2">
{{receivedVal}}
<button ng-click="thisWillGetValFromService()" >update this scope's value</button>
</div>
<script>
var app= angular.module('myApp', []);
app.controller('myCtrl', function($rootScope,$scope,sharedProperties) {
$scope.stringValue = sharedProperties.getString();
$scope.myFunc = function(newValue) {
sharedProperties.setString(newValue);
$scope.stringValue = sharedProperties.getString();
console.log($scope.stringValue);
//I am getting the value here by calling sharedProperties.getString();
$rootScope.$broadcast('greeting', newValue);
};
});
app.controller('myCtrl2', function($scope,sharedProperties) {
$scope.receivedVal = sharedProperties.getString();
console.log($scope.receivedVal);
//But I am not getting the updated value here by calling sharedProperties.getString();
$scope.$on('greeting', function(ev,val){
$scope.receivedVal = val
})
});
app.service('sharedProperties', function() {
var stringValue = 'firstoccurence';
return {
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
},
}
});
</script>
</body>
Above snippet shall solve your problem.
Updated :
Consider a scenario where you have routing configuration defined. So by default only controller 1 and its templates loads in HTML. Then you update ur input box and click OK button. This will save data to service.
Then later on consider on click of some link you re redirecting the app to route of your controller 2 so at this point your controller 2 will get instantiated and $scope.receivedVal = sharedProperties.getString(); this will give you updated value.
Its just a matter of when you load your template (controller) In your case you load both the controllers at a time so you need to use broadcast and on. But if your second component going to load sometime later then you can always use service.
Value is updating in the second controller
But it is not reflecting in the :
<div ng-controller="myCtrl2">
{{receivedVal}}
</div>
Because ng-controller creates new scope
you should write one extra method like in this:
https://codepen.io/amar9312/pen/yRJKGj

Getting the value of ng-model input from controller angular js

I'm trying to get the value of my ng-model input to my controller. The input value has a value and not empty.
Why this code is not working? It says undefined when you alert or console log. What did i missed? really appreciate your help. here is my code
input --> the value is 1
<input type="text" name="idval" ng-model="Data.idval">
js
app.controller('Controller', function($scope, $http){
$scope.fetchvalue = function(){
var id = $scope.Data.idval; // not working
var id = $scope.idval; // even this one
alert(id); // its undefined
$http.post(
"query.php", {
'ID': id,
}
).then(function(response) {
console.log(response.data);
});
}});
Here is a working solution for your code:
You need to declare an object and bind it to ng-model,
$scope.Data = {};
var app = angular.module('myApp', []);
app.controller('formCtrl', function($scope) {
$scope.Data = {};
$scope.fetchvalue = function(){
var id = $scope.Data.idval; // not working
alert(id); // its undefined
}
});
<!DOCTYPE html>
<html lang="en">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="formCtrl">
<form novalidate>
<input type="text" name="idval" ng-model="Data.idval">
<button ng-click="fetchvalue()">Submit</button>
</form>
</div>
</body>
</html>
Here is a working Plunker
I understand,
see you defined id twice, first id get the value from ng-model which must be assigning ng-model value to id variable and you override id with undefined variable called idval.
You can either remove line var id = $scope.idval; or
modify alert(id); as alert($scope.Data.idval)
You need to declare it somewhere before you use it.
$scope.DATA = ""
var id = $scope.Data.idval;
Try this out

AngularJS - two way binding not working using service

I am learning Angular using W3Schools.
I just modified an example about "Services"... The following is the code:
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{hex}}</h1>
</div>
<p>A custom service whith a method that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.service('hexafy', function() {
this.myFunc = function (x) {
return x.toString(16);
}
});
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
When I update the textbox, the "HEX" part is not updating. Why?
Your hexafy.myFunc is called only once when the controller is initialized, hence only the initial value is converted to hex. If you want a function to be called on the value change of a scope variable in runtime, you need filters. AngularJS has a lot of inbuilt filters that are ready to use.
You can also define a custom filter, just like you define services or controllers.
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<p><input type="text" ng-model="num"></p>
<h2>{{num}}</h2>
<h1>{{num | hexafy}}</h1>
</div>
<p>A custom filter that converts a given number into a hexadecimal number.</p>
<script>
var app = angular.module('myApp', []);
app.filter('hexafy', function() {
return function (x) {
return Number(x).toString(16); // Also convert the string to number before calling toString.
}
});
app.controller('myCtrl', function($scope) {
$scope.num = 200;
//$scope.hex = hexafy.myFunc($scope.num);
});
</script>
</body>
</html>
Further reading: AngularJS Filters
NOTE: A filter is a good idea if you're gonna be using the hexafy functionality at multiple places in/across views. Otherwise, it is just an overkill and the $scope.$watch method will work fine for you, as described in other answers
$scope.hex is not updating because there're no way for it update itself.
The hexafy.myFunc is called only once when the controller is loaded for the first time.
If you want want the $scope.hex property to change with num, you might need a watch on the num property.
$scope.$watch('num', function(newVal, oldVal) {
$scope.hex = hexafy.myFunc($scope.num); /// or newVal
}
The function passed in $scope.$watch will be called everytime the value of $scope.num changes.
for more info see https://docs.angularjs.org/api/ng/type/$rootScope.Scope (the watch section)
Hope it helps.
No need of a service here, you can simple use $watch on the num. See below code snippet, it will update your ui, I have updated your controller code, please check.
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.hex = "some default val";
$scope.$watch('num', function(newValue, oldValue) {
$scope.hex = newValue.toString();
});
});
Your Text box is only bind to 'num'. '$scope.hex is not binded to your text box'. So that it is not update when you typing text. You could use '$watch' on 'num'. Read here
app.controller('myCtrl', function($scope, hexafy) {
$scope.num = 200;
$scope.$watch('num', function() {
$scope.hex = hexafy.myFunc(parseInt($scope.num));
});
});

Why does Angular binding not work for me when using ng-include as such

$scope.$apply.() also does not help and just produces an error that digest() is already running. I am changing the header of the page depending on the state name. It works and the header controller does its job, but when a different HtmlTemplate is loaded its controller scope variables aren't binding to it. I have a feeling it's because I am replacing the contents of the <header> element that has the 'ng-controller = HeaderController' attribute and this causes some kind of conflict.
Index.html
<body>
<header data-ng-controller="HeaderController" data-ng-include="headerUrl"></header>
</body>
header.controller.client.js
angular.module('core').controller('HeaderController', ['$scope','$state',
function($scope) {
function setHeader(stateName) {
var headerUrl = '';
switch(stateName) {
case '':
headerUrl = 'PrimaryHeader.client.view.html';
break;
case 'viewtemplate':
headerUrl = 'HeaderForProductDetails.view.html';
break;
default:
headerUrl = 'PrimaryHeader.client.view.html';
}
return headerUrl;
}
$scope.headerUrl = setHeader($state.current.name);
}
]);
PrimaryHeader.view.html
<script type="text/ng-template" id="PrimaryHeader.view.html">
<h2>
Hello I am the primary header template and I bind to the HeaderController scope.
</h2>
</div>
</script>
HeaderForProductDetails.view.html
<script type="text/ng-template" id="HeaderForPrductDetails.view.html">
<div data-ng-controller="HeaderForPrductDetailsController">
<h2>
Hello I am the header for product details and I should be able to bind to my own controller scope and that of my parent. But I don't.
</h2>
<div>{{somevalue}}</div> //this scope variable does not bind
</div>
</script>
headerforproductdetails.controller.client.js
angular.module('core').controller('HeaderForProductDetailsController', ['$scope'
function($scope) {
$scope.somevalue = 'Some test string'; //this does not bind to template, yet console.log() will output it just fine.
}
]);

AngularJS: ng-app inside ng-include

I have a template like this.
<body ng-app="demo" ng-controller="demo">
<div ng-include="/main.html">
</div>
</body>
And the main.html is.
<div ng-app="main" ng-controller="main>
""
</div>
here is the js.
JS-1
var myapp = angular.module('demo', []);
myapp.controller('demo', function($scope,$routeParams, $route,$http) {
$scope.variable="444"
})
JS-2
var mainapp = angular.module('mainapp', []);
myapp.controller('main', function($scope,$routeParams, $route,$http) {
})
Is it possible to access the scope of JS-1 inside JS-2?, if yes how, if no is there any solution to this.Thanks.
It depend what you want to do.
If you want read $scope.variable variable from JS-1, you should see it in JS-2 $scope.
If you want modify $scope.variable form JS-1, you should create method in JS-1:
$scope.changes = function(data){
$scope.variable = data;
}
This method also should be available in JS-2 $scope.
This isn't nice solution but should work.
The best solution is to create service which will provide operations on JS-1 fields.

Resources