Getting values from an object into ng-model - angularjs

I have resource that gets an object:
.factory('Product', ['$resource', function($resource) {
return $resource( 'api/product/:id', { Id: '#Id' }, {
update: { method: 'PUT', isArray: false }
});
}])
I call this resource from the ng-route, in the /edit/product/:sku using 'resolve'
.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/index', {
templateUrl: 'lord/partials/main'
}).
when('/product/edit/:SKU', {
controller: 'EditCtrl',
templateUrl: function(params){ return 'lord/partials/product/edit' },
resolve: {
product: function( Product, $routeParams ){
return Product.get({ id: 101 }).$promise;
}
}
}).
otherwise({
redirectTo: '/index'
});
}]);
In my controller, I receive product successfully:
.controller('EditCtrl', ['$scope', 'product', function ($scope, product) {
console.log(product.measures); // I get the object -> Object {weight: 100, length: 200, width: 180, height: 200}
//Initialize object:
$scope.datos = {};
$scope.datos.measures = {};
However, when i want to "copy" that object to a scope variable, it doesn't work. The scope variable is $scope.datos, which is an object, in a form. I populate this object like this:
<div class="col-md-1">Peso</div>
<div class="col-md-2">
<div class="input-group">
<input type="number" class="form-control" ng-model="datos.measures.weight" >
<span class="input-group-addon">gr</span>
</div>
</div>
<div class="col-md-1">Largo</div>
<div class="col-md-2">
<div class="input-group">
<input type="number" class="form-control" ng-model="datos.measures.lenght">
<span class="input-group-addon">cm</span>
</div>
</div>
<div class="col-md-1">Ancho</div>
<div class="col-md-2">
<div class="input-group">
<input type="number" class="form-control" ng-model="datos.measures.width">
<span class="input-group-addon">cm</span>
</div>
</div>
<div class="col-md-1">Alto</div>
<div class="col-md-2">
<div class="input-group">
<input type="number" class="form-control" ng-model="datos.measures.height">
<span class="input-group-addon">cm</span>
</div>
I tried, in the controller, several methods to copy the value that I receive into the object.
I tried:
angular.copy(product.measures,$scope.datos.measures);
And:
$scope.datos.measures = angular.copy(product.measures);
And:
$scope.datos.measures = product.measures;
$scope.datos.measures.weight = product.measures.weight;
And none of these worked.
However, assigning the product.measures.width into any variable, like $scope.dwidth, works. But this is not what I want, since my object is far more complex.
How can I get to copy the values of the object I receive (product.measures) into another object ($scope.datos.measures) and reflect that value in the with ng-model?
Thank you.

I was able to determine what was happening. I was calling another controller that was resetting these values.
So the route controller was called (EditCtrl) but after that, the controller in the page reset the values.
After that, it was enough with the following code:
angular.copy(product.measures,$scope.datos.measures);
That made the trick and copied the whole object.
Also, I had to change tue $scope.datos.measures.length name to $scope.datos.measures.len due to the Javascript property.

Related

How to dynamically call data from an API when option is selected

Suppose there are two hotels in my options in select tags and I want my h1 to change when I select one of the options. How do I achieve this
I am using POST method to authorize and call data in my reservationCtrl and display the hotel_name in my select tags.
<div class="container">
<div class = "row" ng-controller="reservationCtrl">
<div class="form-group">
<label for="sel1">Select a Hotel:</label>
<select class="form-control" id="sel1">
<option ng-repeat="x in hotels.data">{{x.hotel_name}}</option>
</select>
</div>
</div>
And I am using GET method to call data from another API to display the hotel_name.
<div class="row" ng-controller="showCtrl">
<div class="col-md-4">
<h1 ng-repeat="x in hotel.data">{{x.hotel_name}}</h1>
</div>
</div>
</div>
Here is my showController and I want my hotel id to change like from 72 to 35 when I click one of the options so that it will call data from a different API and display a different name in the headers.
(function(){
angular
.module("reservationModule")
.controller("showCtrl", function($http, $scope, $log){
$http({
method: 'GET',
url: '&hotel_id=72'})
.then(function (response) {
$scope.hotel = response.data;
}, function (reason){
$scope.error = reason.data;
$log.info(reason);
});
});
})();
Here is the reservationController
(function(){
angular
.module("reservationModule")
.controller("reservationCtrl", function($http, $scope, $log){
$http({
url: '',
method: "POST",
data: 'postData',
headers:{ 'Authorization': 'value'}
})
.then(function(response) {
$scope.hotels = response.data;
}
);
});
})();
Yes you can add ng-change and achieve your functionality as below
JS code
var app = angular.module('myApp', []);
app.controller('ctrl1', function($scope) {
$scope.hotels = [{
name: 'Taj',
id: 1
}, {
name: 'Royal',
id: 2
}];
$scope.hotelInfo = {};
$scope.fetchData = function() {
// here call service which will fetch data and assign to hotel data
$scope.hotelInfo = {
address: 'London'
};
}
});
app.controller('ctrl2', function($scope) {
$scope.data = ''
});
HTML code
<div ng-app='myApp'>
<div ng-controller='ctrl1'>
<select ng-options='item as item.name for item in hotels' ng-model='hotel' ng-change='fetchData()'>
</select>
{{hotel}} - {{hotelInfo}}
</div>
</div>
Here is the link Jsfiddle demo
You need to call event on the select box which will call simple function which return the data like following
<select ng-options="size as size.name for size in sizes"
ng-model="item" ng-change="update()"></select>
write javascript code on the update function
Your can use ng-change on select of particular hotel.
In congroller :
$scope.showHotel = function(hotelName){
$scope.selectedHotel = hotelName;
}
<div class="row" ng-controller="showCtrl">
<div class="col-md-4">
<h1 ng-repeat="x in hotel.data" ng-change="showHotel(x.hotel_name)">{{x.hotel_name}}</h1>
</div>
</div>
In view you you can edit like this if you have to display only one hotel name instead of ng-repeat:
<div class="row" ng-controller="showCtrl">
<div class="col-md-4">
<h1>{{selectedHotel}}</h1>
</div>
</div>

AngularJS: Only post non-blank values

I am trying to $http.post a JSON object from a form. I can't seem to find the right syntax. Let's assume my form only takes one value (name). I use ng-model to bind the name to an object called modcampaign.name.
What's the correct syntax to post this to a http service?
Further, what if I had another input box, Description, and only want to bind this to modcampaign.description if the user entered data in the input box? If the input box is empty, I'd like to take the value for .description from another object (like modcampaign2.description).
<form ng-submit="modifyCampaign(selCampaign, newName)" class="form-horizontal" name="modCampaign">
<!-- Modify Name -->
<div class="form-group">
<label class="col-lg-2 control-label" for="modName">Name</label>
<div class="col-lg-8">
<input class="form-control" type="text" id="modName" ng-model="modCampaign.name"/>
</div>
</div>
</form>
This is the script file:
var myApp = angular.module('myApp', []);
myApp.controller('ListController', ['$scope', '$http', function($scope, $http) {
$http.get('js/campaigns.json').success(function (data) {
$scope.campaigns = data;
});
$http.post('js/campaign_mod.json').success(function (data) {
data = $scope.modCampaign;
});
$scope.selCampaign={};
$scope.selectCampaign = function (campaign) {
$scope.toggleCampaign = !$scope.toggleCampaign;
$scope.selCampaign = campaign;
};
$scope.abbrechen = function () {
$scope.toggleCampaign = !$scope.toggleCampaign;
};
$scope.submit = function () {
$http.post('')
}
}]);
You can include something like this in your controller:
$scope.modCampaign = {};
//this gets called on ng-submit
$scope.submitData = function(){
$http.post("api-end-point", $scope.modCompaign).success(function(data, status) {
//handle response etc.
});
}
Your html will have something like this:
<form ng-submit="submitData()" class="form-horizontal" name="modCampaign">
<!-- Modify Name -->
<div class="form-group">
<label class="col-lg-2 control-label" for="modName">Name</label>
<div class="col-lg-8">
<input class="form-control" type="text" id="modName" ng-model="modCampaign.name"/>
<textarea ng-model="modCampaign.description"/></textarea>
</div>
</div>
</form>
you can use JSON.stringify()
example
$http({
method: "POST",
url: 'http://www.example.com/posturl',
data : JSON.stringify($scope.modcampaign)
}).success(function(response){
console.log(response);
// write any action after post success
})
<form ng-submit="modifyCampaign(modCampaign)" class="form-horizontal" name="modCampaign">
<!-- Modify Name -->
<div class="form-group">
<label class="col-lg-2 control-label" for="modName">Name</label>
<div class="col-lg-8">
<input class="form-control" type="text" id="modName" ng-model="modCampaign.name"/>
</div>
</div>
<div class="form-group">
<label class="col-lg-2 control-label" for="modDescription">Description</label>
<div class="col-lg-8">
<input class="form-control" type="text" id="modDescription" ng-model="modCampaign.description"/>
</div>
</div>
</form>
var myApp = angular.module('myApp', []);
myApp.controller('ListController', ['$scope', '$http', function($scope, $http) {
$scope.modifyCampaign = function(modCampaign) {
console.log(modCampaign)
alert(modCampaign.name) // name:"jane"
alert(modCampaign.description) // description: "hello"
$http.post('js/campaign_mod.json', { name: modCampaign.name, description: modCampaign.description }).success(function (data) {
console.log(data)
});
}
}]);
This method lets you bind all the form value to one object and then you can decode the value in your controller file, below is a link to a working example
http://codepen.io/anon/pen/VjYLvg

angularjs and ui-router - controller not working

The full source code.
I don't understand why $scope not working in my LoginGuideCtrl controller. I try click on login button and should show a <p> with new data but the $scope is not updating...
DonĀ“t forget I'm trying to achieve a modular design.
I have the following code:
guides.js
var guides = angular.module('main.guides', ['ui.router']).config(function ($stateProvider) {
$stateProvider.
state('guides.login', {
url: '/login',
templateUrl: 'modules/guides/views/login.html',
controller: 'LoginGuideCtrl'
}).
...
state('guides.mobile', {
url: '/web',
template: '<div>guildes mobile</div>',
controller: 'ListCtrl'
});
});
controller.js
var guides = angular.module('main.guides');
guides.controller('IndexCtrl', function() {
console.log('Index');
})
.controller('LoginGuideCtrl', function($scope) {
console.log('feck');
$scope.checkLogin = function(){
$scope.message = "Welcome "+$scope.name+"!"
};
})
.controller('ListCtrl', function() {
console.log('List');
})
login.html
<div class="form-group col-sm-2">
<label for="usr">Name:</label>
<input type="text" class="form-control" id="usr" ng-model="name">
</div>
<div class="form-group col-sm-2">
<label for="pwd">Password:</label>
<input type="password" class="form-control" id="pwd" ng-model="password">
</div>
<button type="button" class="btn btn-default" ng-click="checkLogin()">Login</button>
<p ng-model="message"></p>
ng-model is used with <input> tags to capture user input, by two way binding with your model value.
Since a <p> tag does not collect user input, it won't work with ng-model. Instead just do a one way binding with the value using the curly brackets:
<p>{{message}}</p>

How an autocomplete/lookahead directive can be used in a decoupled way for multiple separate inputs using separate services?

Currently I have three inputs that I need to use autocomplete on that look something like that:
<div class="actor-container">
<input type="text" class="actors"/>
</div>
<div class="movie-container">
<input type="text" class="movies"/>
</div>
<div class="director-container">
<input type="text" class="directors"/>
</div>
I also have my own autocomplete directive
<div my-autocomplete="my-autocomplete" service="serviceName"></div>
The autocomplete is getting a serviceName as an input to access different data repositories (search in different pools) using an $injector
What is the best AngularJS practice to connect this directive with the other three inputs?
I was thinking of putting it in each input like that:
<div class="actor-container">
<input type="text" class="actors" my-autocomplete="my-autocomplete" service="actorService"/>
</div>
<div class="movie-container">
<input type="text" class="movies" my-autocomplete="my-autocomplete" service="movieService"/>
</div>
<div class="director-container">
<input type="text" class="directors" my-autocomplete="my-autocomplete" service="directorService"/>
</div>
But is this good practice? Or the directive should be placed "outside" once and then use shared service/broadcast/watch etc to communicate with the each of the three inputs using three separate controllers?
<div class="actor-container" ng-controller="addActorCtrl">
<input type="text" class="actors"/>
</div>
<div class="movie-container" ng-controller="addMovieCtrl">
<input type="text" class="movies"/>
</div>
<div class="director-container" ng-controller="addDirectorCtrl">
<input type="text" class="directors"/>
</div>
<div my-autocomplete="my-autocomplete" service="serviceName(how to pass that??)"></div>
What should happen is someone should type in each of those fields and the appropriate autocomplete based on a serviceName and what the user input should pop up. Then the user will click on one of the returned entries and this should be added to the right container. I also wonder where the code object.movies.push() (e.g for the movies - when the user clicks a suggested movie) will be placed..
I would really appreciate if you could provide an example with some code because I am fairly new in AngularJS and I think this would be useful for others too :)
Thanks
This is what I did and I think it is a good practice:
I have a controller for each of the inputs and I add the directives in each of those:
<div ng-controller="addActorCtrl">
<div suggest-dir="suggest-dir" service="actorService" input-string="{{input1}}" select="addActor(suggestEntry)"></div>
<input id="actors" name="actors" type="text" placeholder="" class="input-medium" ng-model="input1"/>
</div>
<div ng-controller="addMovieCtrl">
<div suggest-dir="suggest-dir" service="movieService" input-string="{{input2}}" select="addMovie(suggestEntry)"></div>
<input id="actors" name="actors" type="text" placeholder="" class="input-medium" ng-model="input2"/>
</div>
<div ng-controller="addDirectorCtrl">
<div suggest-dir="suggest-dir" service="directorService" input-string="{{input3}}" select="addDirector(suggestEntry)"></div>
<input id="actors" name="actors" type="text" placeholder="" class="input-medium" ng-model="inpu23"/>
</div>
This is my autocomplete directive
angular.
module('myApp.suggestModule').
directive('suggestDir',function(){
// Runs during compile
return {
scope: {
inputString: '#',
service: '#',
select: '&'
},
controller: [
'$scope',
'$injector',
function($scope, $injector) {
this.inputChanged = function(inputString){
$injector.get($scope.service).suggest(inputString,
function(data){
$scope.suggestEntries = data;
}
);
};
this.entryWasClicked = function(suggestEntry){
$scope.select({suggestEntry:suggestEntry})
}
}],
restrict: 'A',
templateUrl: 'suggestMenu/views/suggest-menu.html',
link: function(scope, element, attrs, controller) {
scope.$watch('inputString', function(newValue, oldValue) {
controller.inputChanged(newValue);
});
}
};
})
This is my autocomplete entry directive which when it is clicked is calling the entryWasClicked from its parent suggestDir. It's parent calls $scope.select but is a & parameter so it is the function that is being passed in <div suggest-dir select="functionToBeCalled/>
directive('suggestEntryDir',function(){
// Runs during compile
return {
require: '^suggestDir',
restrict: 'A',
templateUrl: 'suggestMenu/views/suggest-entry.html',
link: function(scope, element, attrs, controller) {
var suggestEntry = scope.$eval(attrs.suggestEntry);
element.bind('click', function(e){
scope.$apply(function(){ controller.entryWasClicked(suggestEntry)})
});
}
};
});
This is one of the wrapper controllers (that I used for each of the inputs) so everything is decoupled:
controller('addActorCtrl',[
'$scope',
function($scope){
var obj= $scope.obj;
$scope.addActor= function (actor){
if(!obj.actors){
obj.actors = [];
}
obj.actors.push(actors);
};
}]);
This is one of the services (the actorService). Services bring data from the database and behave as repositories:
angular.
module('myApp.actorModule').
constant('restAPI','http://localhost/project/').
factory('actorService',['$http','restAPI',function($http,restAPI){
return {
latest: function (callback){
$http({
method: 'GET',
url: '',
cache: true
}).success(callback);
},
find: function(id, callback){
$http({
method: 'GET',
url: restAPI+'actor/'+id,
cache: true
}).success(callback);
},
suggest: function(stringInput,callback){
$http({
method: 'GET',
url: restAPI+'actor/suggest/'+stringInput,
cache: true
}).success(callback);
},
update: function(id,actor, callback){
$http({
method: 'PUT',
url: restAPI+'actor/'+id,
data: actor
}).success(callback);
}
}
}])
Finally this is the template for my suggestion directive:
<div id="suggestions" ng-show="suggestEntries.length>0 && inputString.length>0">
<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>
<div class="viewport">
<div id="suggestions-list" class="overview">
<div class="types" ng-repeat="suggestEntry in suggestEntries">
<div suggest-entry-dir="suggest-entry-dir" suggest-entry="suggestEntry"></div>
</div>
</div>
</div>
<div class="close" style="width:10px; cursor: pointer; height:10px; background-color:#aaaaff; position:absolute; top: 4px; right: 4px;"></div>
</div>
and this is for the suggestEntry
<div class="suggest-entry suggest-{{suggestEntry.label}}">
{{suggestEntry.textIndexed}}
</div>

How hide a drop-down list when the model is empty in angularjs?

I need to hide a drop-down list when the model is empty and to show it when there are values in the model.
I have a service to get the values.
angular.module('myApp.services', ['ngResource'])
.factory('OptionsSelect', ['$resource',
function ($resource) {
return $resource('http://myapi/miapp/optionselect/1', {}, {
query: {
method: 'GET',
params: { id: '1' },
isArray: false
}
});
}
])
The possible result is:
{"1":"red","5":"blue","34":"blue"}
or
<pre>
{}
</pre>
In the controller:
$scope.optionsSelect = OptionsSelect.query();
The view is:
<div class="form-group" ng-hide="isHide()">
<select class="form-control" ng-options="key as value for (key, value) in optionsSelect">
</div>
You can view the code in jsfiddle: http://jsfiddle.net/finsi/LMJXC/38/
Hi I've created jsbin for you please have a look. You should add model to you select directive and use $promise like it is below. I hope that will help.
HTML:
<div class="form-group" ng-show="optionsSelect">
<select class="form-control"
ng-model="option.color"
ng-options="key as value for (key, value) in optionsSelect">
</div>
JS:
app.controller('firstCtrl', function($scope, OptionsSelect){
$scope.optionsSelect = {};
OptionsSelect.query().$promise.then(function(optionSelectCollection){
angular.copy(optionSelectCollection, $scope.optionsSelect);
});
});
So these selected optionsSelect objects are undefined, they stay undefined if nothing is returned and become objects if something is returned. Can you just hide them if they're undefined? Such as in this fiddle...http://jsfiddle.net/LMJXC/40/
<div class="form-group" ng-hide="optionsSelect === undefined">
and
<div class="form-group" ng-hide="optionsSelect2 === undefined">

Resources