I am new to angular
in the following controller i need to access the object store in my html. But it is not working. Any help
(function () {
'use strict';
angular.module('app').controller('BookController', ['$scope', function ($scope) {
$scope.book = {
id: 1,
name: 'Harry Potter',
author: 'J. K. Rowling',
stores: [
{ id: 1, name: 'Barnes & Noble', quantity: 3 },
{ id: 2, name: 'Waterstones', quantity: 2 },
{ id: 3, name: 'Book Depository', quantity: 5 }
]
};
}]);
});
<div ng-controller="BookController">
{{book.stores}}
</div>
You need to first invoke your anonymous function first using () after the final closing bracket and before the final semi-colon so that the last line looks like this: })();.
You should define angular module first and then amend it with the angular component like controller, service , factory, directive, filters, etc.
angular.module('app', [])
then add ng-app="app" on your page.
Markup
<div ng-app="app" ng-controller="BookController">
{{book.stores}}
</div>
Plunkr Here
Update
If suppose you have multiple store inside the stores object, and you want to show them on the html, then for that you could ng-repeat directive. It will repeat each element on html
<div ng-repeat="s in book.stores">
<span>{{s.name}}</span>
<input type="text" ng-model="s.name" />
<input type="numeric" ng-model="s.quantity" />
</div>
Updated Plunkr
Related
JS:
angular
.module('app', [])
function MainCtrl() {
var ctrl = this;
ctrl.selectionList = [
{ id: 1, name: 'apple'},
{ id: 2, name: 'banana'},
{ id: 3, name: 'grapes'},
{ id: 4, name: 'carrot'}
];
ctrl.selectedThing = ctrl.selectionList[0].name;
}
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
HTML:
<div class="row">
<div class="col-sm-3 col-xs-12 unit">
<select
ng-model="ctrl.selectedThing"
ng-options="selections.name as selections.name for selections in ctrl.selectionList">
</select>
</div>
</div><!--end of first row-->
So this code creates four different selections.
The problem is that when I choose an option, let's say for example "apples" on one selection, all the other selections become apples too. Is there any way to solve this with ng-options or should I just write the select in HTML?
You definitely want to use ng-options, as that isn't the issue here. The problem you are seeing is most likely because the ng-model on all of your select elements is the same ctrl variable. So when you update one of them, it changes a single variable that is bound to all four dropdowns. You either need to setup up an array for your selected items, or four different instances of a selected variable.
ctrl.selectedThings = [ctrl.selectedList[0].name, '', '', ''];
Then in your view you can do this...
<select
ng-model="ctrl.selectedThings[rowIndex]"
ng-options="selections.name as selections.name for selections in ctrl.selectionList">
</select>
Not the most robust solution if you are going past 4 items, but you should be able to adapt it to be dynamic.
Your code is working fine, can you check and confirm?!
(function ()
{
var app = angular.module("app", []);
function HomeController()
{
var vm = this;
vm.selectionList = [
{ id: 1, name: 'apple'},
{ id: 2, name: 'banana'},
{ id: 3, name: 'grapes'},
{ id: 4, name: 'carrot'}
];
}
app.controller("HomeController", [HomeController]);
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<title>Angular JS App</title>
</head>
<body>
<div class="container" ng-controller="HomeController as homeCtrl">
<div class="row">
<div class="col-sm-3 col-xs-12 unit">
<select
ng-model="homeCtrl.selectedThing"
ng-options="selections.name as selections.name for selections in homeCtrl.selectionList">
</select>
<pre>{{homeCtrl.selectedThing}}</pre>
</div>
</div><!--end of first row-->
</div>
</body>
</html>
If you have ng-model="ctrl.selectedThing" for all of your <select> tags, they will all change to the same selection because they're using the same scope property. Think of it like having 4 variables referencing the same data: if you change one, access any of the variables will retrieve the same result.
You need to bind all of your selects to a different property on scope, so ctrl.selectedThing1,2,...n. That's not very scalable, but that would fix your problem.
I am fairly new to angular and am working with a client that wants a dropdown allowing users to select their neighborhood which is then saved in a cookie to load upon return. I am able to save cookie but am having trouble getting dropdown selected neighborhood to load proper template.
Here is the html:
<select id="mNeighborhood" ng-model="mNeighborhood" ng-options="neighborhood.id as neighborhood.name for neighborhood in neighborhoods" ng-change="saveCookie()"></select>
And then, I have added the following in html:
<div ng-view=""></div>
Here is the app.js code:
var app = angular.module('uSarasota', ['ngCookies', 'ngRoute']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
template: '<div><h1 style="margin: 200px;">This is our main page</h1></div>'
})
.when('/downtown', {
templateUrl: "templates/downtown.html"
})
.otherwise({
template: '<div><h1 style="margin: 200px;""><strong>NOTHING TO SEE HERE</strong></h1></div>'
})
});
//Select Neighborhood
app.controller('myNeighborhood', ['$scope', '$cookies', function($scope, $cookies) {
$scope.neighborhoods = [{
name: "My Neighborhood",
id: 0
}, {
name: "All of Sarasota",
id: 1
}, {
name: "Downtown",
url: "/downtown",
id: 2,
}, {
name: "North Sarasota",
id: 3
}, {
name: "Lakewood Ranch",
id: 4
}, {
name: "Longboat Key",
id: 5
}, {
name: "St. Armands Circle",
id: 6
}, {
name: "Southside Village",
id: 7
}, {
name: "Siesta Key",
id: 8
}, {
name: "Gulf Gate",
id: 9
}];
//Set Cookie so when user returns to site, it will be on their neighborhood
$scope.mNeighborhood = parseInt($cookies.get('sNeighborhood')) || 0;
$scope.saveCookie = function() {
$cookies.put('sNeighborhood', $scope.mNeighborhood);
};
}]);
This all works fine to save and load user selection, but am having trouble finding solution to get template based on selection. So, should I add url to the array for each neighborhood and if so, how do I get the link?
Basically you need to change the URL programatically on selection of dropdown. For achieving this thing you need to first change you ng-options to return object on selection. And then using that object get url property from it to load particular template.
Markup
<select id="mNeighborhood"
ng-model="mNeighborhood"
ng-options="neighborhood.name for neighborhood in neighborhoods"
ng-change="saveCookie()">
</select>
Code
$scope.saveCookie = function() {
var mNeighborhood = $scope.mNeighborhood;
$cookies.put('sNeighborhood', mNeighborhood.id);
//do add $location dependency in controller function before using it.
$location.path(mNeighborhood.url);
};
Update
On initial Load the value should be set as object as per new implementation.
$scope.mNeighborhood = {}; //at the starting of controller
//the other code as is
//below code will get the object from the neighborhoods array.
$scope.mNeighborhood = $filter('filter')($scope.neighborhoods, parseInt($cookies.get('sNeighborhood')) || 0, true)[0];
$scope.saveCookie = function() {
var mNeighborhood = $scope.mNeighborhood;
$cookies.put('sNeighborhood', mNeighborhood.id);
//do add $location dependency in controller function before using it.
$location.path(mNeighborhood.url);
};
JS
angular.module('bindExample', []).controller('ExampleController', ['$scope', function($scope) {
$scope.gridFields = {
id: {
width: 50
},
price: {
width: 60
},
};
$scope.allData = {
'one': {
id: '1234qwe',
price: 900
},
'two': {
id: 'asdadw',
price: 1700
},
'three': {
id: '342sdaw',
price: 1200
},
};
$scope.edit = function(row) {
console.log(row);
$scope.buffer = $scope.allData[row];
}
}]);
HTML
<div ng-app="bindExample">
<div ng-controller="ExampleController">
<table>
<tbody>
<tr ng-repeat="(row, data) in allData">
<td ng-repeat="(field, option) in gridFields" ng-bind="data[field]"></td>
<td><button ng-click="edit(row)">edit</button></td>
</tr>
</tbody>
</table>
<div>
<input type='text' ng-model="buffer.id"/>
</div>
<div>
<input type='text' ng-model="buffer.price"/>
</div>
</div>
</div>
After click on edit, values go to $scope.buffer variable from $scope.allData, and the inputs use the buffer as model, but when input is change the values in allData variable changing as well, but i don't want this, this is why is try to pass the values to other...
Problem illustrated here: JSFIDDLE
Any idea?
Use angular.copy()
$scope.buffer = angular.copy($scope.allData[row]);
Javascript will hold reference if assigned data is either function or object or array.
It provides a great benifit to the developer in many ways . but if you wanna to remove reference you have to clone it.
using angular
$scope.buffer = angular.copy($scope.allData[row]);
First things, you're going to get unexpected results in ng-repeat if you use a parent object literal rather than an array (Angular doesnt guarantee that it will iterate through keys in order):
$scope.allData = [ //you're better off using an Array
'one': {
id: '1234qwe',
price: 900
},
'two': {
id: 'asdadw',
price: 1700
},
'three': {
id: '342sdaw',
price: 1200
},
]; //see above
Secondly, the reason this is happening is that Javascript copies everything as a reference unless it is a primitive, so when you do this:
$scope.buffer = $scope.allData[row];
You're actually just storing a pointer to the original object $scope.allData[row] in $scope.buffer.
To do a "deep copy" yo ucan use angular.copy as suggested by #moncefHassein-bey in his answer.
I have a model, which will be related to a number of other models. Think of a stack overflow question, for example, where it is a question related to tags. The final Object might look as follows before a POST or a PUT:
{
id: 28329332,
title: "checkboxes that append to a model in Angular.js",
tags: [{
id: 5678,
name: "angularjs"
}, {
id: 890,
name: "JavaScript"
}]
}
So far, I have the following controller:
.controller('CreateQuestionCtrl',
function($scope, $location, Question, Tag) {
$scope.question = new Question();
$scope.page = 1;
$scope.getTags = function() {
Tag.query({ page: $scope.page }, function(data) {
$scope.tags = data;
}, function(err) {
// to do, error when they try to use a page that doesn't exist
})
};
$scope.create = function() {
$scope.question.$save(function(data) {
$location.path("/question/" + data.id);
});
};
$scope.$watch($scope.page, $scope.getTags);
}
)
So I display all of the tags, paginated, on the page. I want them to be able to select the given tags and append it to my model so that it can be saved.
How can I create a checkbox interface where it updates the $scope.question with the selected other models?
EDIT: think I might be part of the way there
<div class="checkbox" ng-repeat="tag in tags.objects">
<label><input
type="checkbox"
ng-change="setTag(tag.id)"
ng-model="tag"
> {{ tag.name }}
</div>
Then on the controller
$scope.setTag = function(id) {
Tag.get({id: id}, function(data) {
// don't know what now
})
}
Basically, it takes a directive to approach your goal Take a look at the plunker I wrote for you. As you can see, in the list of selected tags the text property of each tag is displayed, it means that the object structure is kept. In your case, you would bind the $scope.question.tags array as the collection attribute and each tag from the $scope.tags as the element attribute.
Here a codepen for multiple check-boxes bound to the same model.
HTML
<html ng-app="codePen" >
<head>
<meta charset="utf-8">
<title>AngularJS Multiple Checkboxes</title>
</head>
<body>
<div ng:controller="MainCtrl">
<label ng-repeat="tag in model.tags">
<input type="checkbox" ng-model="tag.enabled" ng-change="onChecked()"> {{tag.name}}
</label>
<p>tags: {{model.tags}}</p>
<p> checkCount: {{counter}} </p>
</body>
</html>
JS
var app = angular.module('codePen', []);
app.controller('MainCtrl', function($scope){
$scope.model = { id: 28329332,
title: "checkboxes that append to a model in Angular.js",
tags: [{
id: 5678,
name: "angularjs",
enabled: false
}, {
id: 890,
name: "JavaScript",
enabled: true
}]
};
$scope.counter = 0;
$scope.onChecked = function (){
$scope.counter++;
};
});
I found a great library called checklist-model worth mentioning if anyone is looking up this question. All I had to do was this, more or less:
<div class="checkbox" ng-repeat="tag in tags">
<label>
<input type="checkbox" checklist-model="question.tags" checklist-value="tags"> {{ tag.name }}
</label>
</div>
Found this on googling "directives for angular checkbox".
My code is like this
<body ng-app="myApp" ng-controller="MainCtrl">
<div>Name only
<input ng-model="search.name" />
<br />
<table id="searchObjResults">
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
<tr ng-repeat="friendObj in friends | filter:search:strict | limitTo:1">
<td>{{friendObj.name}}</td>
<td>{{friendObj.phone}}</td>
</tr>
</table>
</div>
<div>
<button type="button" id="btn_submit" ng-click="submitForm()">Get rates</button>
</div>
angular.module('myApp', []).controller('MainCtrl', ['$http', '$scope', function ($http, $scope) {
$scope.friends = [{
name: 'John',
phone: '555-1276'
}, {
name: 'Mary',
phone: '800-BIG-MARY'
}, {
name: 'Mike',
phone: '555-4321'
}, {
name: 'Adam',
phone: '555-5678'
}, {
name: 'Julie',
phone: '555-8765'
}, {
name: 'Juliette',
phone: '555-5678'
}];
$scope.submitForm = function () {
// i want to get the data here
};
}]);
As you can see at a time only one friend will be active on my screen. when I press my submit button, I want that data (filtered single row) to be the only value on my current $scope.friends so that I can send it to an external service as the selected data. Can any one point out what i need to do here
Fiddle
Note: I can't change the position of this button.
Why not make your button part of the table row, since there will only ever be one? Here is a JSFiddle showing it working in that fashion.
The ng-click function handler for the button can then simply take a parameter that is the actual friendObj you are interested in:
<button type="button" ng-click="submitForm( friendObj )">Get rates</button>
EDIT: There is actually a way to do this if you can't move the button; make the ng-repeat operate over a NEW array, which will be accessible outside of the ng-repeat. So your ng-repeat statement becomes:
<tr ng-repeat="friendObj in newArray = (friends | filter:search:strict | limitTo:1)">
And then your button can simply reference the one-element array:
<button type="button" ng-click="submitForm( newArray )">Get rates</button>
Updated Fiddle here :-)
Try this:
$scope.submitForm = function () {
var data = $filter('filter')($scope.friends, $scope.search.name);
};
Fiddle here.
If you put the filter in the controller instead of the view, you could set a variable like $scope.result that the submitForm function could use. For example, in your HTML, you could add an ng-change directive to your search field like so:
<input ng-model="search.name" ng-change="updateResult()" />
Then, instead of using ng-repeat, you'd use ng-show to show the one result, or hide the row if there is no result:
<tr ng-show="result">
<td>{{result.name}}</td>
<td>{{result.phone}}</td>
</tr>
Then in your controller:
$scope.search = {name: ''};
$scope.updateResult = function() {
$scope.result = $filter('filter')($scope.friends, $scope.search.name)[0];
}
$scope.updateResult();
// ...
$scope.submitForm = function() {
// $scope.result can be used here
}
EDIT: The advantage of this approach is it's a bit DRYer because you don't re-filter inside submitForm. MarcoS's approach has the advantage of being a lot shorter!