Preserve empty field in model with Angular - angularjs

If I have an angular form like this
<form name="myForm">
<input type="text" required ng-model="field1" />
<input type="text" ng-model="field2" />
</form>
When I access the model it will only hold those fields that have values so if both fields have values json will be {"field1":"value1","field2":"value2"}. If only field1 is has a value json will be {"field1":"value1"}. Can I instruct Angular to keep empty fields in the model with null values?
UPDATE:
My controller looks like below. I'm loading the data as json from the server. When the data comes from the server I get this {"field1":"value1","field2":"value2"} but when saveContent is run and only field1 has a value the server gets this {"field1":"value1"}.
var myApp = angular.module('myApp', []);
myApp.controller('contentEditController', ['$scope', '$http',
function ($scope, $http) {
$scope.saveContent = function () {
$http.post("/api/ContentData", $scope.formdata);
};
$scope.loadContent = function (contentId) {
$http.get("/api/ContentData/" + contentId)
.success(function (response) {
$scope.formdata = response;
});
}
}]);
So fields that had values when they came from the server don't get sent back as empty.
-Mathias

Initialize the values on the scope in the controller,
.controller('formcontroller', [ '$scope', function($scope){
$scope.field1 = "";
$scope.field2 = "";
})];

The proper way to do this is to initialize the variables. You should in your controller have
$scope.field1 = ""
$scope.field2 = ""
or a more crude way to do is in to use ng-init (try not to use ng-init if you can)
<input type="text" required ng-model="field1" ng-init="field1=''"/>
<input type="text" ng-model="field2" ng-init="field2=''"/>

Related

Getting value of ng-change field in my angularjs controller

I have this line in my view:
<input placeholder="Search" type="text" ng-change="searchChange()" ng-model="mySearch" ng-model-options="{debounce: 1000}">
And then inside my controller I have:
angular.module('app.controllers', [])
.controller('listViewCtrl', ['$scope', '$stateParams', '$http',
function ($scope, $stateParams, $http) {
$http.get('http://www.domain.co.uk/api/search.php').
then(function(response) {
$scope.food = response.data;
});
$scope.searchChange = function() {
console.log($scope.mySearch);
};
}])
But this is giving me "undefined".
How can I reference the value of the mySearch input field in my controller?
Your input field might be located within a sperate scope, which is not updated correctly. ngIf and ng-repeat are common examples for directives creating a separate sub-scope. (See this article for more information around scopes)
Dotted scope variables
To protect yourself from such issues you might either store your variables inside objects.
<input placeholder="Search" type="text" ng-change="searchChange()" ng-model="my.search" ng-model-options="{debounce: 1000}">
$scope.my = {search: ""};
$scope.searchChange = function() {
console.log($scope.my.search);
};
Named Controllers
Or name your controllers specifically as recommended in the angular style guide Y030.
Pass variable as parameter
A third option is simply passing the variable as parameter to the function:
<input placeholder="Search" type="text" ng-change="searchChange(mySearch)" ng-model="mySearch" ng-model-options="{debounce: 1000}">
$scope.searchChange = function(mySearch) {
console.log(mySearch);
};

Angular modify and resubmit http.get request using buttons on page

I'm pulling data from elastic search using Angular http.get and displaying the output using angular.
The initial concept is working fine, however what I would like to do is add a button to the page to be able to run a frequently required query which will modify the data that is displayed and exclude records containing specific words or phrases.
I think that this can be achieved by having the button set the value of a variable within the scope of the http.get request and then resubmititng the get request.
So far I have:
<body>
<form>
<input type="text" placeholder="RemoveEntires" class="form-control" ng-model="formData.input1">
<input type="button" value="RemoveEntries containing text" ng-click='DocView()'>
</form>
<script>
var app = angular.module('DisplayDoc', []);
var baseUrl = "http://elasticserver:9200/app/_search?q=product:balls";
var queryURL = baseUrl + "+!color:"; + formData.input1;
var completeURL = queryURL + "&sort=DateTime&size=1000&default_operator=AND";
app.controller('DocView', function($scope, $http) {
$http({method: 'GET', url: completeURL})
.success(function(response) {$scope.jsondata = response.hits.hits;});
});
</script>
If I enter "red" in the form, I would like it resubmit the http.get request to elasticsearch which would then exclude the red balls from the balls products that are returned.
This is not currently working for me. Any ideas?
You could do something like this.
Controller:
.controller('MainCtrl', function ($scope, $http) {
$scope.search = '';
var baseUrl = "http://elasticserver:9200/app/_search?q=product:balls+!color:";
$scope.submit = function() {
$http.get(baseUrl + $scope.search + "&sort=DateTime&size=1000&default_operator=AND")
.then(function(response) {
$scope.jsondata = response.hits.hits;
});
}
});
And then build the form like this:
<form novalidate>
<input type="text" ng-model="search">
<button type="submit" ng-click="submit()">Search</button>
</form>

How to send data from one controller to another controller in angularjs

Below is my playlist json data coming from playlist controller.
{
"id":18,
"file":{"url":"/uploads/playlist/file/18/01_-_MashAllah.mp3"},
"event_id":23,"created_at":"2015-11-11T10:33:52.000Z",
"updated_at":"2015-11-11T10:33:52.000Z",
"name":"01 - MashAllah.mp3"
},
{
"id":19,
"file":{"url":"/uploads/playlist/file/19/02_-_Laapata.mp3"},
"event_id":19,"created_at":"2015-11-11T10:50:01.000Z",
"updated_at":"2015-11-11T10:50:01.000Z",
"name":"02 - Laapata.mp3"
}
Now i want to bind id and name to a playerController am i doing something like this
<div ng-controller="playlistsController">
<div ng-repeat="playlist in playlists">
<div ng-controller='PlayerController'>
<input type=hidden ng-model="ID" ng-init="ID=playlist.id">
<input type=hidden ng-model="Name" ng-init="Name=playlist.name">
</div>
</div>
</div>
and in controller
.controller('PlayerController',['$scope',function($scope) {
console.log($scope.ID);
console.log($scope.name);
}]);
but the console is showing undefined.
i don't know where i am going wrong as i am new to angular.
METHOD 1:
The best way to share data between controllers is to use services. Declare a service with getters and setters and inject into both the controllers as follows:
service:
app.service('shareData', function() {
return {
setData : setData,
getData : getData,
shared_data : {}
}
function setData(data) {
this.shared_data = data
}
function getData() {
return this.shared_data
}
})
With your service defined, now inject into both the controllers and use the parent controller (in your case) to set the data as follows:
app.controller('playlistsController', function(shareData) {
//your data retrieval code here
shareData.setData(data);
})
And finally in your child controller, get the data:
app.controller('PlayerController', function(shareData) {
$scope.data = shareData.getData();
})
METHOD 2:
Since, you have to communicate data from parent controller to child controller, you can use $broadcast as follows:
parent controller:
//retrieve data
$scope.$broadcast('setData', data);
And receive the data in child controller:
$scope.$on('setData', function(event, args) {
$scope.data = args;
})
First controller code is executed, then angular starts proceed html this controller is attached to. So just move your variable initialization to controller:
$scope.Name = $scope.playlist.name;
$scope.ID = $scope.playlist.id;
or just use original variables (if you dont need copy of them)
<input type=hidden ng-model="ID=playlist.id">
<input type=hidden ng-model="Name=playlist.name">
or you may leave it as is - it works disregarding that you don't see values in log.
You should use $parent:
JSFiddle
HTML:
<div ng-controller="playlistsController">
<div ng-repeat="playlist in playlists">
<div ng-controller='PlayerController'>
<input type="text" ng-model="$parent.playlist.id">
<input type="text" ng-model="$parent.playlist.name">
</div>
</div>
</div>
JS:
app.controller('PlayerController', function ($scope, $sce) {
console.log($scope.$parent.playlists);
});

Get value from HTML page to angularJS file

I tried to get the HTML page value to angularJS function , The below steps are which i tried.
HTML page :
<label class="item-input item-stacked-label">
<span class="input-label cont_det_label">First Name</span>
<p class="contact_display" id="txtFirstName" ng-model="testName">Satya</p>
</label>
angularJS Page :
.controller('SocialNetworkCtrl', ['$scope','$http','$state','ContactsService','$ionicNavBarDelegate','$ionicLoading','$ionicPopup',function($scope, $http, $state, ContactsService, $ionicNavBarDelegate, $ionicLoading,$ionicPopup) {
$scope.showUserProfile = function() {
$state.go("linkedin");
var firstname = (document.getElementById("txtFirstName").value);
}
}])
So I need var firstname = Satya ?? Is it correct way please guide me to access this value .
var firstName = $scope.testName
<input ng-model="testName" />
testName is the ng-model name that you have give. It will be automatically binded to your controller. No need the get the value using document.getElementById
Wrong usage , why ng-model in <p> tag??
Update
Change your fiddle with the following code, it will work. Also make sure framework is selected properly (as in the image)
<div ng-app ng-controller="testController">
<input ng-model="testDataName" ng-change="check()" /> {{testDataName}}
After ng-change : {{checkName}}
</div>
function testController($scope) {
$scope.testDataName="Dummy Name";
$scope.check = function () {
$scope.checkName=$scope.testDataName;
console.log($scope.checkName);
};
}
its a text node, you will require .innerHTML or '.innerText', .value is for form inputs
var firstname = (document.getElementById("txtFirstName").innerHTML);
and don't use ng-model on a p element, change it to like this
<p class="contact_display" id="txtFirstName">{{testName}}</p>
just use $scope.testName to get the value, no need for firstname = (document.getElementById("txtFirstName").innerHTML); querying DOM for value is jQuery style, use angular the $scope for 2 way bindings
Read more at official doc
Update here is updated function on loginCtrl
.controller('loginCtrl', ['$scope', function ($scope) {
$scope.testNameData = 'Satya';
$scope.doLogin = function() {
alert($scope.testNameData);
};
}])
If you really want to go jQuery way here is what you can do, its not recommended, you should use angular directive to do DOM manipulation
$scope.showUserPro = function() {
$ionicLoading.show();
// Here i need the value of <p tag>
var name = document.getElementById("txtFirstName"),
firstNameFromHtmlPtag = name.innerText;
console.log(firstNameFromHtmlPtag, 'Doing API Call 1');
}

AngularJS Typeahead prepopulation

I have a typeahead that I want to contain a description but store the Id.
I'm currently doing it something like this...
<input type="text"
ng-model="SelectedWarehouse.Info"
typeahead="whs.info for whs in warehouses($viewValue)"
typeahead-on-select="POHeader.warehouseId=$item.id;"
class="form-control input-sm "
id="whs" placeholder="Warehouse"
ng-disabled="isReadOnly"
typeahead-wait-ms="500"
ng-enter="say('hello');" />
Where the jsonp that I get from the $scope.warehouses function looks something like this:
([{"id":"10", "info": "Lakeland (10)"}, {"id":"11", "info": "Denver (11)"}])
of course along with the appropriate jsonp callback info -- this is just an example
The sloppy part of it is this:
When the screen opens the $scope.SelectedWarehouse is not populated with anything.
I then wrote something to pre-populate the SelectedWarehouse but there has to be a better way to do this using typeahead.
What's the right/good/best (pick one) way to do this?
Another problem is not knowing when my async call will actually populate my objects. Promises promises... I thought I'd try using the ng-change function call hoping that when the data gets populated the ng-change function would fire ... so far that didn't work. I'm not quite done experimenting with that though...
Here's part of my $resource factory. What would I need to do to get a success call working with this?
ipoModule.factory('SearchRepository', function ($resource) {
return {
get: function (txt) {
return $resource('/api/Search?SearchText=' + txt).query()
},
getBuyers: function () {
return $resource('api/Buyers').query()
},
getVendors: function () {
return $resource('api/Vendors').query()
},
getVendorSearch: function (txt) {
return $resource('api/Vendors/' + txt + "?callback=JSON_CALLBACK").query()
}, ....
Any ideas?
i think something like this might work. You can bind the typeahead to a collection instead of a method, and update that collection on keypress by fetching values from the server. You can also watch for changes on the collection so you will know when your data is about to be populated.
See Demo: http://jsfiddle.net/yfz6S/17/
view.html
<div style="margin: 40px;">
<div ng-controller="WarehousesCtrl">
<pre>query: {{query | json}}</pre>
<pre>selectedWarehouse: {{selectedWarehouse | json}}</pre>
<input
class="form-control input-sm"
ng-model="query"
typeahead="warehouse.info for warehouse in warehouses | filter:$viewValue"
typeahead-on-select="selectedWarehouse = $item;"
ng-keypress="fetchWarehouses();"
/>
</div>
</div>
controller.js
.controller('WarehousesCtrl', ['$scope', '$http', '$q', function ($scope, $http, $q) {
$scope.query = null;
$scope.selectedWarehouse = null;
$scope.warehouses = [];
$scope.fetchWarehouses = function() {
$http.jsonp(
'http:/mysite.com/mywarehouses?q=' + $scope.query
).success(function(data){
$scope.warehouses = data.warehouses;
}).error(function(){
// this request will fail so lets just set some dummy warehouses
$scope.warehouses = [
{id:1, info:"Toronto"},
{id:2, info:"Tobermory"},
{id:3, info:"Oshawa"},
{id:4, info:"Ottawa"},
{id:5, info:"Ajax"},
];
});
};
}]);
I made my own work-around because I couldn't get the pre-population to work with a typeahead.
<input type="text"
ng-model="POHeader.SelectedWarehouse"
typeahead="whs.info for whs in warehouses($viewValue)"
typeahead-on-select="POHeader.warehouseId=$item.id;"
class="form-control input-sm "
id="whs" placeholder="Warehouse"
ng-disabled="isReadOnly"
typeahead-wait-ms="500" />
I changed the view that populates the POHeader to include a field called SelectedWarehouse. This is my pre-formatted typeahead value which looks the same as the whs.info returned from the typeahead warehouses list.
It's not ideal but it works and I can't afford to waste more time on this.

Resources