Angular js + ng-repeat + alphanumeric index not working - javascript

I have created one Nav Controller in Angular JS as mentioned below.
weatherApp.controller('navCtrl', ["$scope", "$localStorage", function($scope, $localStorage){
if($localStorage.user_email){
var navItems = new Array();
navItems["/"] = 'Home';
navItems["/logout"] = 'Logout';
$scope.navItems = navItems;
}
else{
var navItems = new Array();
navItems["/"] = 'Home';
navItems["/login"] = 'Login';
$scope.navItems = navItems;
}
$scope.test = "test";
}]);
I am calling this controller in index.html as shown below.
<ul class="nav navbar-nav" ng-controller="navCtrl">
<li ng-repeat="(url, navItem) in navItems">
{{ navItem }}
</li>
</ul>
if I keep navItems indexes alphanumeric then it does not load values but if I keep its indexes numeric, it show menu items.
Is there any way by which I can use alphanumeric indexes in ng-repeat?

I think you need a diferent data structure. Something like this:
https://jsfiddle.net/relferreira/3aexpfk5/
JS:
angular.module('app', []);
angular.module('app')
.controller('MainController', mainController);
mainController.$inject = ['$scope'];
function mainController($scope){
var vm = this;
vm.navItems= [
{ path: '/', name: 'Home'},
{ path: '/login', name: 'Login'},
];
}
HTML:
<div data-ng-app="app">
<div data-ng-controller="MainController as mainVm">
<ul class="nav navbar-nav">
<li ng-repeat="navItem in mainVm.navItems">
{{ navItem.name }}
</li>
</ul>
</div>
</div>

Your syntax for ng-repeat is correct.
However, do not use Array. Initialize your objects as:
var navItems = {};
As a side note, keeping user email in LocalStorage sounds like a very unusual thing (if this is a client-server app), but of course this ultimately depends on your use case.

Related

Dynamic HTML partial based on REST response

I have an application I am building using an Angular JS front end and a REST-based API back end feeding a MySQL database. There are REST calls made from the front end to the back end to populate or retrieve data in the database. I want to add a drop down selection box to my angular JS front end home page. I want the selection to trigger a REST call to the database, to retrieve a specific value and have that value become a part of a dynamically loaded html partial.
As an example, the drop down would select a model of a car (Toyota Corolla, Honda Accord, etc.) When you select that model, the controller would make a REST call to the appropriate table(s) to get the rest of the information for that car (MPG, size, weight, etc.) Once it did this, it would load a partial HTML on the page that was a template HTML file but with dynamic content. So the page loaded would be /#/carInfo?toyotaCorolla. The template partial html file would load and then the tables on the template would populate with the response from that REST call. So I would essentially have a single template for that page, but it would call a new VERSION of the page based on what was selected.
I am thinking about this in my head and I do not have my application code with me. This question is not for the actual code solution, but for someone to either write up some pseudo code or point me to a demo/example online that is similar to this...if it is even possible. I am doing searches on my own, but I may be searching for the wrong terminology to get this accomplished. Any pointers or help on this would be appreciated.
UPDATE:
Now that I am home, here is a snippet of the code I am having issues with.
<ul class="nav navbar-nav">
<li></li>
<li class="dropdown">
<a href="javascript:void(0)" data-target="#" class="dropdown-toggle" data-toggle="dropdown">
Select a car...
<b class="caret"></b></a>
<ul class="dropdown-menu">
<li ng-model="selectedCar.value" ng-repeat="x.car for x in cars"
ng-change="selectedCarChanged()"></li>
</ul>
</li>
</ul>
That is not populating correctly. I have the same ng code for a <select> implementation using ng-options instead of ng-repeat. I was hoping it would be a simple transition, but the CSS version using the lists is not working.
Please find the code snippet below. Hope this will be helpful
car-list.html
<div ng-controller="carListController">
<select ng-model="selectedCar" ng-change="onSelectCar(selectedCar)">
<option ng-repeat="car in cars">{{car}}</option>
</select>
</div>
carListController.js
app.controller('carListController', function($scope, $location) {
$scope.carList = ['Honda', 'Toyota', 'Suzuki', 'Hyundai'];
$scope.onSelectCar = function(car) {
$location.path('#/carInfo').search({carInfo: car});
}
});
carInfo.html
<div class="carDetails">
<span>Car Name: {{car.name}}</span>
<span>Car Model: {{car.model}}</span>
<span>Car Year: {{car.year}}</span>
<span>Car Size: {{car.size}}</span>
</div>
carInfoDetailsController.js
app.controller('carInfoController', function($scope, $location, $http) {
$scope.car = {};
$scope.init= function() {
$http.get('url/' + $location.search('carInfo'), function(response) {
$scope.car = response;
});
};
$scope.init();
});
appConfig.js
app.config(function($routeProvider){
$routeProvider.when('/carInfo'{
templateUrl: "carInfo.html",
controller: "carInfoController"
});
});
something like:
//in a service
(function() {
function MyService($http) {
var myService = {};
MyService.accessMultiTool = function(){
var args = Array.from(arguments);
var method, url, authorization;
args.forEach(function(item){
if('method' in item){
method = item.method;
}else if ('url' in item){
url = item.url;
}else if ('authorization' in item){
authorization = item.authorization;
}
});
delete $http.defaults.headers.common['X-Requested-With'];
return $http({
method: method,
origin: 'http://someclient/',
url: url,
headers: {'Authorization': authorization}
}).error(function(status){generate some error msg});
};
return MyService;
}
angular
.module('myApp')
.factory('MyService', ['$http', MyService]);
})();
//in a controller
(function () {
function MyCtrl(MyService) {
var myController = this;
this.car_model_options = ["Honda", "Chevy", "Ford", "Nissan"];
this.bound_car_model_obj = {
model: null
};
this.getCarModel = function(){
MyService.accessMultiTool({method: 'GET'}, {url: 'http://somebackend/api/cars/' + myController.bound_car_model_obj.model}, {authorization: this.activeMember.auth}).then(function(data){
myController.setCurrCarModel(data);
});
this.setCurrCarModel = function(data){
myController.currently_selected_car_model = data;
};
};
};
angular
.module('myApp')
.controller('MyCtrl', ['MyService', MyCtrl]);
})();
//in a template
<div ng-controller="MyCtrl as mycontroller">
<select data-ng-init="this.bound_car_model_obj.model = mycontroller.car_model_options[0]" data-ng-model="this.bound_car_model_obj.model" data-ng-options="option for option in mycontroller.car_model_options" >
</select>
<table>
<tr ng-repeat="car in mycontroller.currently_selected_car_model>
<td>{{car.someproperty}}>/td>
<td>{{car.someotherproperty}}>/td>
</tr>
</table>
</div>

How do I display this json file correctly in ng-repeat?

I'm trying to create a Store page for my website. I want to display the following json file in ng-repeat:
{
"cupcakes": {
"Vanilla": [
{"price":"9.99", "stock":"20", "amount":"8",
"ingredients":"flour, sugar, vanilla extract",
"popular":true}
],
"Maple": [
{"price":"9.99", "stock":"15", "amount":"8",
"ingredients":"flour, sugar, maple syrup",
"popular":true}
]
},
"cookies": {
"Vanilla": [
{"price":"7.99", "stock":"50", "amount":"12", "ingredients":"flour, sugar, vanilla extract"}
],
"Maple": [
{"price":"7.99", "stock":"50", "amount":"12", "ingredients":"flour, sugar, maple syrup"}
]
}
}
I want to display the type item (cupcake or cookie) then the type of each item (vanilla or maple) then the unique attributes and be able to filter and search through them. I'm thinking I may have to restructure my json file, but I'm not sure. Should I sort out the items ahead of time in my controller with a forEach? Here is my controller:
angular.module('root', [])
.controller("index", ['$scope', '$http', function ($scope, $http) {
$scope.name = null;
$scope.email = null;
$scope.comments = null;
$scope.reason = null;
$scope.employees = [];
$scope.items = [];
$http.get('http://localhost:8000/employees.json').then(function(result) {
$scope.employees = result.data.records;
});
$http.get('http://localhost:8000/inventory.json').then(function(result) {
$scope.items = result.data;
});
$scope.isEnabled = function() {
if ($scope.name && $scope.email && $scope.comments) {
return false;
}
else {
return true;
}
}
}])
In Javascript, almost everything is an array. You can iterate over an array of objects or, in an object you are iterating over his properties.
The following script should do the work.
<div ng-repeat="(itemLabel, itemValue)in items">
{{itemLabel}}
<div ng-repeat="(flavorLabel, flavorValue)in itemValue">
{{flavorLabel}}
<div ng-repeat="object in flavorValue">
<div ng-repeat="property in object">
{{property}}
</div>
</div>
</div>
</div>
jsfiddle
Here is a way for showing your data using ng-repeat:
<div ng-repeat="(foodKey, foodVal) in foods">
<b>{{foodKey}}</b>
<div ng-repeat="(typesKey, typesVal) in foodVal">
<span>{{typesKey}}</span>
<ul ng-repeat="types in typesVal">
<li ng-repeat="(key, val) in types">
{{key}} : {{val}}
</li>
</ul>
</div>
</div>
Of course it will only work if foods is the json you posted in your answer.
Here is a working jsFiddle.
For more information on ng-repeat see here.
Just going through your JSON.
<div ng-repeat="(key, value) in inventory">{{key}}
<ul>
<li ng-repeat="(material_key, material_value) in value">{{material_key}}
<ul>
<li ng-repeat="(options_key, options_value) in material_value[0]">{{options_key}} - {{options_value}}</li>
</ul>
</li>
</ul>
<br>
Have a look at this plunker. I hope this will solve you problem.
you need multiple ng-repeaters hope this plunker is your requirement
you can do anything with the keys of your JSON in javascript , by converting the JSON to object by
JSON.parse(json);
later on you can access any key and that will be an object/hashmap to loop or sort
So in your case, your API result can be parsed like
var resultData = JSON.parse(result.data);
Later you can do ng-repeat in your view some thing like
[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'

Return data from object and show in <ul> via AngularJS

I have a controller that receive from server the JSON below:
"[{\"nome\": \"Ricardo Andrade\"}]"
My controller is removing the \ by parsing the JSON, my controller is:
app.controller("userLogado", function ($scope, $http) {
//$http.get('web/core/components/home/nav.json').
$http.get('http://localhost:2099/api/autenticacao/NomeUsuarioLogado').
success(function (data) {
debugger;
var result = json_parse(data);
var sNome = '';
$.each(result, function(key, item) {
sNome = item.nome;
});
})
});
My question is, how can I take the result of this controller and show in my HTML using AngularJS?
I tried to use an Alert and got the right name like this: "Ricardo Andrade".
Thanks in advance!
Its as simple as putting attaching the result to the controller.
Once you get the result you want, just attach it to scope.
app.controller("myCtrl", function ($scope, $http) {
$scope.result = "Ricardo Andrade"
});
And the HTML
<div ng-controller="myCtrl">
{{result}}
</div>
If you have more than one name, you will need to ng-repeat the names.
<div ng-controller="myCtrl">
<ul ng-repeat='name in result'>
<li>{{name}}</li>
</ul>
</div>
<ul>
<li ng-repeat="names in result">
[{{$index + 1}}] {{names.nome}}
</li>
</ul>
Have a look at ngRepeat:
Docs: https://docs.angularjs.org/api/ng/directive/ngRepeat
W3Schools: http://www.w3schools.com/angular/angular_directives.asp
EDIT:
I hear it's better to use ng-repeat with arrays, so you might want to do that if you feel like it:
Your controller:
$scope.allNames =[];
app.controller("userLogado", function ($scope, $http) {
//$http.get('web/core/components/home/nav.json').
$http.get('http://localhost:2099/api/autenticacao/NomeUsuarioLogado').
success(function (data) {
debugger;
var result = json_parse(data);
for(var name in result) {
$scope.allNames.push(angular.copy(result[name]));
}
})
});
Your HTML:
<ul>
<li ng-repeat="names in allNames">
[{{$index + 1}}] {{names.nome}}
</li>
</ul>
The ul list must be inside a container with ng-controller attribute.
E.g.
<div ng-controller="userLogado">
<ul list here>
</div>
The benefit of using an array with ng-repeat is that you can filter (Read here) and order (Read here) your data.

AngularJS: how to split functionality into many controllers

I have a single controller in my application http://jsfiddle.net/HKF9h/:
<div ng-controller="MyCtrl">
All Items:
<ul>
<li ng-repeat="item in items">{{item }} -
like it
</li>
</ul>
Items you liked:
<ul>
<li ng-repeat="item in likedItems">{{item }}
</li>
</ul>
</div>
<script type="text/javascript">
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.items= ['foo', 'bar', 'z'];
$scope.likedItems = [];
$scope.like = function (item) {
if($scope.likedItems.indexOf(item) === -1) {
$scope.likedItems.push(item);
}
}
</script>
}
I would like move all 'favoriting' functionality into sep controller that can be reused later. Here's what i did, but repeater is not showing likedItems anymore. What did I do wrong? http://jsfiddle.net/MR8wz/
<div ng-controller="MyCtrl">
All Items:
<ul>
<li ng-repeat="item in items">{{item }} -
<a href=""
ng-controller="FavoriteCtrl"
ng-click="like(item)">like it</a>
</li>
</ul>
Items you liked:
<ul ng-controller="FavoriteCtrl">
<li ng-repeat="item in likedItems">{{item }} //this one does not trigger
</li>
</ul>
</div>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.items= ['foo', 'bar', 'z'];
}
function FavoriteCtrl($scope) {
$scope.likedItems = [];
$scope.like = function (item) {
console.log('you liked', item); //this one is displayed
if($scope.likedItems.indexOf(item) === -1) {
$scope.likedItems.push(item);
}
}
}
You shouldn't really be relying on controller inheritance for sharing data. It's a bad case of close coupling.
In Angular, if you want to share data, you're advised to use services/factories because:
They're easily injectable anywhere you need them
They're easily mockable
They're easily testable
FIDDLE
var myApp = angular.module('myApp',[]);
myApp.factory('Favorite', function(){
var likedItems = [];
function like(item) {
console.log('you liked', item); //this one is displayed
if(likedItems.indexOf(item) === -1) {
likedItems.push(item);
}
}
function getLikedItems(){
return likedItems;
};
return {
like: like,
getLikedItems: getLikedItems
};
});
function MyCtrl($scope, Favorite) {
$scope.favorite = Favorite;
$scope.items = ['foo', 'bar', 'z'];
}
function FavoriteCtrl($scope, Favorite) {
$scope.likedItems = Favorite.getLikedItems();
}
<div ng-controller="MyCtrl">
All Items:
<ul>
<li ng-repeat="item in items">{{item }} -
<a href=""
ng-controller="FavoriteCtrl"
ng-click="favorite.like(item)">like it</a>
</li>
</ul>
Items you liked:
<ul ng-controller="FavoriteCtrl">
<li ng-repeat="item in likedItems">{{item }}
</li>
</ul>
</div>
You use ng-controller directive two times
like it
and
<ul ng-controller="FavoriteCtrl">
It creates two different scope this is the reason it doesn't work. So if you move
$scope.likedItems = []; in parent controller MyCtrl then it works. Updated
fiddle

Instantiate and initialize controller in AngularJS

I have a problem instanciating controller with Angular. I have a main controller AlkeTypeDefListController from which I want to dynamically create/remove controllers of type AlkeTypeDefController, so I have done that :
Code of AlkeTypeDefListController:
// Create main controller
Alke.controller('AlkeTypeDefListController', ['$scope', '$controller', function($scope, $controller)
{
var primitives =
[
];
// Add some properties to the scope
angular.extend($scope,
{
typedefs : primitives,
addTypeDef : function()
{
var controller = $controller("AlkeTypeDefController", {$scope:$scope.$new()});
$scope.typedefs.push(controller);
}
});
}]);
Code of AlkeTypeDefController:
// Create main controller
Alke.controller('AlkeTypeDefController', ['$scope', '$controller', function($scope, $controller)
{
// Add some properties to the scope
angular.extend($scope,
{
name : "New Type",
fields : [],
addField : function()
{
}
});
}]);
The html code is this one:
<div id="typedefs-editor" ng:controller="AlkeTypeDefListController">
<button ng:click="addTypeDef()">Add</button>
<button>Remove</button>
<div id="typedef-list">
<ul class="list">
<li ng:repeat="typedef in typedefs">{{typedef.name}}</li>
</ul>
</div>
</div>
The problem does not really come from the instantiation (which works fine), but from the initialization. In fact, when the new "li" appears when I push the "Add" button, the text "New type" (initialized in the controller) does not appear.
I think it is about the scope or something like that, but I can't really find how to fix this.
I wanted to know if this method seems correct, and also how could I fix the problem I have.
Thanks
Reading the code, I understand that you want to create typedefs dynamically and those typedef items have to be controlled by an AlkeTypeDefController.
In that case I would create AlkeTypeDefController using ng:controller directive, so you don't need to create the controller programmatically, because then you would need to attached it to the view and that's just what the ngController directive does for you.
Notice AlkeTypeDefListController does not create a AlkeTypeDefController controller, this is done in the view
Demo on Plunker
Controllers:
.controller('AlkeTypeDefListController', ['$scope', function($scope) {
var primitives = [];
$scope.typedefs = primitives;
$scope.addTypeDef = function() {
var typeDef = { name: 'New Type' };
$scope.typedefs.push(typeDef);
}
}])
.controller('AlkeTypeDefController', ['$scope', function($scope) {
$scope.addField = function() {
alert('add Field');
}
}]);
View (notice how ng-controller directive is specified in li element):
<div id="typedefs-editor" ng:controller="AlkeTypeDefListController">
<button ng:click="addTypeDef()">Add</button>
<button>Remove</button>
<div id="typedef-list">
<ul class="list">
<li ng:repeat="typedef in typedefs" ng:controller="AlkeTypeDefController">
{{typedef.name}}
</li>
</ul>
</div>
In the code above, ngRepeat is going to create a new $scope for each typedef. AlkeTypeDefController then decorates that scope with functions and values.
I hope it helps
When you call $controller("AlkeTypeDefController") it will essentially call new on the AlkeTypeDefController constructor and give you back the return value not the scope. You are assign the name attrubute to the scope though so it is not being accessed in your html when you have typedef.name.
Try changing your AlkeTypeDefController to this:
Alke.controller('AlkeTypeDefController', function() {
this.name = "New Type";
this.fields = [];
this.addField = function() {};
});
Then you can instantiate it with: var controller = $controller("AlkeTypeDefController"); and you shouldn't need to worry about creating nested scopes.
If I get what you're saying correctly then I think I'd try to leverage the power of a custom directive here instead of dynamically generating controllers.
plunker
Controller:
Alke.controller('alkeTypeDefListController', ['$scope', '$controller',
function($scope, $controller) {
var primitives = [];
var addTypeDef = function() {
$scope.typedefs.push({
name: 'new name'
});
};
var removeTypeDef = function(){
$scope.typedefs.pop();
};
var properties = {
typedefs: primitives,
addTypeDef: addTypeDef,
removeTypeDef: removeTypeDef
};
// Add some properties to the scope
angular.extend($scope, properties);
}
]);
Directive:
Alke.directive('alkeTypeDef', function() {
return {
restrict: 'A',
scope: {
typeDef: '=alkeTypeDef'
},
template: '{{typeDef.name}}',
link: function(scope, element, attr) {
var properties = {
fields: [],
addField: function() {
}
};
angular.extend(scope, properties);
}
};
});
HTML:
<div ng-app='Alke'>
<div id="typedefs-editor" ng-controller="alkeTypeDefListController">
<button ng-click="addTypeDef()">Add</button>
<button ng-click="removeTypeDef()">Remove</button>
<div id="typedef-list">
<ul class="list">
<li alke-type-def='typedef' ng-repeat="typedef in typedefs"></li>
</ul>
</div>
</div>
</div>
If you want a controller then you can use one in the directive instead of a linking function.

Categories

Resources