AngularJS Data Binding with Getter and Setter Service Method - angularjs

I'm struggling to understand how data binding and Service works togheter in AngularJS.
I've 1 controller and 1 service.
My service:
myAppServices.factory('SharedData',['$http',function($http){
var _data = {
"first_prop" :{
"name": "first_prop",
"info": "infofirst_prop"
},
"second_prop" :{
"name": "second_prop",
"info": "infosecond_prop"
}
};
return {
getProp: function (name) {
return _data[name];
},
setProp: function (name,value) {
_data[name] = value;
}
};
}])
My controller code:
webAppControllers.controller('FirstCtrl', ['$scope', '$http','SharedData',
function ($scope, $http,SharedData) {
$scope.data = angular.copy(SharedData.getProp("first_prop"))
$scope.print = function()
{
console.log(SharedData.getProp("first_prop"));
}
$scope.modify = function()
{
SharedData.setProp("first_prop",$scope.data)
}
}
]);
And this is my view:
<form role="form">
<div class="form-group">
<label for="nome">Name</label>
<input type="text" ng-model="data.name" class="form-control" id="name" placeholder="Modify the name...">
</div>
<div class="form-group">
<label for="info">Info</label>
<input type="text" ng-model="data.info" class="form-control" id="info" placeholder="Modify the info ...">
</div>
<button ng-click="modify()" class="btn btn-default">Modify</button>
<button ng-click="print()" class="btn btn-default">Print</button>
</form>
If i modify the view, overriding value in the form, and then i click on print button, console.log return me values store in services(into private variable _data), and this is what i excpected.
Then if i click on modify button, and again print button, this time cosole.log shows me modified values that was saved on private var _data in my service. Also this behavior is expected.
The strange thing appear when after i did this interaction with my webapp, i again modify value in the form and click on print button without clicking on modify button. Values stored in service are modified even if i never click modify button and so i never call SharedData.setProp() method.
With the method angular.copy(), i expected to create new variable(a new copy of a variable), and so if i modify this "$scoped" variable i expected it was impossible modify directly private _data variable in my service.
Why this happens? Are there a method to modify and access private variable in service only by some defined method?
Thanks in advance.
Best regard,
Alessandro.

After you click setProp, the object in SharedData and in the scope is the same object.
To solve this, call this line again after you call "modify()":
$scope.modify = function()
{
SharedData.setProp("first_prop",$scope.data)
// grab another copy of the first_prop object, or else its the same reference.
$scope.data = angular.copy(SharedData.getProp("first_prop"));
}
There are other ways to solve this, such as in setProp, pass angular.copy($scope.data), etc.
Always be aware that when you pass objects in javascript, the pass by reference, not by value.

Related

Angular JS - How to change the value of an input from the event of another element

I have this html:
<div ng-controller="My.MarkdownEditorController">
<a target="_default" ng-click="changeValue()" class="btn btn-info">Copy Organisation Address to Member</a>
</div>
The Angular controller for the click is:
angular.module("umbraco").controller("My.MarkdownEditorController",
function ($scope, $http) {
$scope.changeValue = function () {
//changes value but it doesn't save
//what is the Angular way to do this correctly
document.getElementById('title').value= document.getElementById('title').value + '2';
};
});
How do I change the value of the adjacent text box with id "title" correctly?
The above code modifies the value, but it doesn't save.
I think that's because I am not changing it the Angular way.
The html of the input I am trying to modify is:
<input type="text" id="title" name="textbox" ng-model="model.value" class="umb-property-editor umb-textstring textstring ng-pristine ng-untouched ng-valid ng-isolate-scope ng-valid-val-server ng-not-empty ng-valid-required" val-server="value" ng-required="model.validation.mandatory" aria-required="false" aria-invalid="False" ng-trim="false" ng-keyup="change()">
I got this working but not sure if it is correct:
angular.module("umbraco").controller("My.MarkdownEditorController",
function ($scope, $http) {
$scope.changeValue = function () {
var title = $("#title");
title.val("this is how to do it");
setTimeout(function(){ title.trigger("input") }, 10);
};
});
Your input: <alue" ng-keyup="change()">
You have javascript value model.value and html input value. These two are connected via ng-model:
After you change scope value $scope.model.value = ... angularjs will update html input value.
After user changes html input value, angularjs will update your scope value.
You should nealy never change html input value directly, you should change scope value (it wont trigger ng-keyup or ng-change).
P.S. avoid using ng-keyup in inputs - there is copy-paste and drag-drop that may change input as well.

AngularJS - How to pass data from View (HTML) to Controller (JS)

I am really new to AngularJS. I want to pass some object from View (HTML) to my controller (JS).
Actually my Client will send me data in HTML and I have to take that data and process that data in my controller and then display the processed output on screen. He will be using some back-end technology called ServiceNow - https://www.servicenow.com/ .
All the solutions I saw had some event like click event or change event, but in my case this has to be done on page load.
I m using Input type hidden for passing the data to the controller, seems like it's not working.
So is there any other way I can do this ?
Here's the code I am trying to use
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing">
</div>
app.controller('progressController', function($scope) {
console.log($scope.testingmodel.testing);
});
It says undefined when I console.log my variable in Controller.
You're doing console.log(...) too early. At this time your controller doesn't have any information from the view.
The second problem is that you're binding the view to a variable in controller and not the other way around. Your $scope.testingmodel.testing is undefined and it will obviously the value in the view to undefined.
Solution
Use ng-init to initialize the model and the controller's hook $postLink to get the value after everything has been initialized.
Like this
<div ng-controller="progressController" >
<input type="hidden" ng-model="testingmodel.testing" ng-init="testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function($scope) {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($scope.testingmodel.testing);
};
});
Edit: extra tip
I don't recomment using $scope for storing data since it makes the migration to newer angular more difficult.
Use controller instead.
Something like this:
<div ng-controller="progressController as $ctrl" >
<input type="hidden" ng-model="$ctrl.testingmodel.testing" ng-init="$ctrl.testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function() {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($ctrl.testingmodel.testing);
};
});
You should use the ng-change or $watch
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing" ng-change="change()">
</div>
app.controller('progressController', function($scope) {
$scope.change = function(){
console.log($scope.testingmodel.testing);
}
});
Or:
app.controller('progressController', function($scope) {
$scope.$watch('testingmodel.testing', function(newValue, olValue){
console.log(newValue);
}
});
If you use ng-change, the function is only called if the user changes the value in UI.
If you use $watch anyway, the function is called.
You can't use value attribute for set or get value of any control, angularJS use ngModel for set or get values.
Here You should try like this way
app.controller('progressController', function($scope) {
//from here you can set value of your input
$scope.setValue = function(){
$scope.testingmodel = {}
$scope.testingmodel.testing = 'ABCD';
}
//From here you can get you value
$scope.getValue = function(){
console.log($scope.testingmodel.testing);
}
});
if you want to bind from html side then you should try like below
<input type="text" ng-model="testingmodel.testing">
<input type="hidden" ng-model="testingmodel.testing">

angularjs -how to clear the form data from a clear button outside sitting outside the form

I have a form with a submit button which works fine. However I need to clear the form data from a clear button which is sitting outside the form on top right of the page. The clear button exist in a parent controller and sits above the form in top right header. The form sent from the clear button always comes up as undefined, which is because the clear button is not part of the form.
How do I pass the same instance of the form to clear? How do I clear the data? If this is a design issue I still need a workaround.
Here is a fiddle I have created to mimic that. Any help will be appreciated.
https://jsfiddle.net/SobDan/vj67rtb2/
<div ng-app>
<div class="col-md-10">
<h2>Todo</h2></div>
<div class="col-md-2">
<button class="btn pull-right" ng-click="clear(TodoForm)"> Close</button>
</div>
<br>
<div ng-controller="TodoCtrl">
<form name="TodoForm" ng-submit="addTodo()" name="testForm">
<input type="text" ng-model="todoText" size="30" placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
function MainCtrl($scope) {
$scope.clear = function(form) {
alert(form); // the form is undefined
if (form.$dirty)
form.setPristine(); // clean this form
else
alert("form not dirty");
};
};
function TodoCtrl($scope) {
$scope.todoText = "test";
$scope.addTodo = function() {
alert("Submitted");
$scope.todoText = "";
// submit logic works fine
};
}
You should use $broadcast to communicate between controllers rather than trying to access the form which is outside scope.
Here is the fiddle and the explanation below
$broadcast function is used to broadcast events to all child $scope. Any interested child $scope can register to listen for the event using $on function. This functionality is used to communicate between controllers.
In your case, we signal to clear the form by broadcasting an event called clearForm from $rootScope. The TodoCtrl $scope listening on the event clearForm will receive a signal to clear form fields.
app.controller("MainCtrl", function($scope, $rootScope) {
$scope.clear = function(form) {
$rootScope.$broadcast("clearForm");
};
});
app.controller("TodoCtrl", function($scope) {
$scope.$on("clearForm", function() {
if ($scope.testForm.$dirty) {
$scope.testForm.$setPristine();
$scope.todoText = "";
} else {
alert("form not dirty");
}
});
});
AngularJS 1.1.x +
$scope.form.$setPristine() is only available from AngularJS version 1.1.x.
$setPristine() will only set the form status to pristine and will not clear the form field. You need to manually clear it by nullifying the $scope variables which will be reflected on the screen.
if ($scope.testForm.$dirty) {
$scope.testForm.$setPristine();
$scope.todoText = "";
}
AngularJS 1.0.x +
$setPristine function is not available in 1.0.x version.
The example Fiddle in your question seem to be configured to 1.0.x
In 1.0.x you simply clear the $scope variables
$scope.$on("clearForm", function() {
$scope.todoText = "";
});

pre-populated form data is undefined in service

jQuery:
$("#inputParentName").val(response.name);
HTML/Angular Form:
<form role="form" ng-submit="addParentService.addParent()">
<div class="form-group">
<label for="inputParentName">Name</label><input class="form-control" id="inputParentName" value="" type="text" ng-model="addParentService.inputParentName" />
</div>
...
<button class="btn btn-default" type="submit">Submit</button>
</form>
The following code when run diplays my name correctly in the input box.
However in my service when I try to see what the value is for inputParentName I get an undefined error. But, when I type something in to the textbox for inputParentName the typed in value displays.
Controller Code:
myapp.controller('AddParentController', function ($scope, addParentService) {
$scope.addParentService = addParentService;
});
Service Code:
myapp.service('addParentService', function () {
var vm = this;
vm.parent = [];
vm.addParent = function () {
alert(vm.inputParentName);
};
});
What can I do differently so I can get the pre-loaded data to register so that my service recognizes the data?
This is just basic code that I'm trying to get working. I realize it isn't pure AngularJS. I am just trying to see how I can get this to work. I will refactor with directives after everything works as I think it should.
If you want the initial value to be "something" when the view displays, you can (technically) use ng-init, though the docs tell us expressly NOT to do this.
The only appropriate use of ngInit is for aliasing special properties
of ngRepeat, as seen in the demo below. Besides this case, you should
use controllers rather than ngInit to initialize values on a scope.
But if you're just trying to test something, ng-init would look like:
<input ng-model="test.val" ng-init="test.val='something'" />
The preferred way though would be to add the value to the controller $scope.
<input ng-model="test.val" />
Then in your controller:
myapp.controller('MyCtrl', function ($scope) {
$scope.test = {
val: 'something'
}
});
#jme11 and This Answer gave me the insight to the following way I figured out how to get this to work:
jQuery code for Facebook logic:
$("#inputParentName").val(response.name);
$("#inputParentEmail").val(response.email);
$("#inputParentBirthday").val(response.birthday);
angular.element(document.getElementById('inputParentName')).scope().$apply();
angular.element($('#inputParentName')).scope().setName(response.name);
angular.element($('#inputParentEmail')).scope().setEmail(response.email);
angular.element($('#inputParentBirthday')).scope().setBirthday(response.birthday);
My Controller code:
$scope.setName = function (val) {
addParentService.inputParentName = val;
}
$scope.setEmail = function (val) {
addParentService.inputParentEmail = val;
}
$scope.setBirthday = function (val) {
addParentService.inputParentBirthday = val;
}
Service Code:
vm.addParent = function () {
alert(vm.inputParentName);
alert(vm.inputParentBirthday);
alert(vm.inputParentEmail);
alert(vm.inputParentCellPhone);
alert(vm.inputParentCarrier);
};
Now when I'm adding my Parent the values pre-populated from Facebook are usable in my service code.
Again - Thanks to jme11 for helping me solve this.

Send values of ng-model to angular controller

I have four different inputs and want to send value of changed input to controller without pressing send button or whatever.
How i got it all inputs should to have next syntaxis.
<input ng-model="borderRadius" ng-change="change()">
<input ng-model="background" ng-change="change()">
Or not?
I want to get them in my app.js
control.controller('generatorOptions', function ($scope) {
$scope.buttonStyle = {
"border-radius" : " -- here is value of it -- ",
"background" : " -- here is value of it -- "
};
});
Update: That is working just fine, but how can i optimise code? https://github.com/tanotify/Button-style-generator/blob/master/public/assets/scripts.min.js
First you need to define in your controller:
control.controller('generatorOptions', function ($scope) {
$scope.buttonStyle={};
$scope.change = function() {
console.log("borderRadius value:"+$scope.buttonStyle.borderRadius);
console.log("background value:"+$scope.buttonStyle.background);
};
});
This is your view:
<input ng-model="buttonStyle.borderRadius" ng-change="change()">
<input ng-model="buttonStyle.background" ng-change="change()">
It means, that first you need define object(buttonStyle) in you controller, than this object is accesseble in you view and in view you will define new properties(radius and background) of your object which you can access in controller by object.

Resources