AngularJS dynamically populate details from json based on item selected - javascript

I am trying to create a page where you have few items in a list group which when selected should show more details.
Please view the example here http://plnkr.co/edit/Oava3pA9OTsm80K58GdT?p=preview
How can I populate the details from the json file based on the item that is selected in the list group?
This is what I have so far.
html:
<div ng-controller=ItemsController>
<h3>Test</h3>
<div class="row">
<div class="col-md-4">
<div class="panel panel-default">
<ul class="list-group">
<a class="list-group-item" ng-repeat="item in itemDetails">{{item.name}}</a>
</ul>
</div>
</div>
<div class="col-md-8">
<div class="panel panel-default">
<h2>Name: </h2>
<br />Address Line 1:
<br />Address Line 2:
<br />Suburb:
<br />Phone:
<br />Email:
</div>
</div>
</div>
</div>
script:
var myItemsApp = angular.module('myItemsApp', []);
myItemsApp.factory('itemsFactory', ['$http', function($http){
var itemsFactory ={
itemDetails: function() {
return $http(
{
url: "mockItems.json",
method: "GET",
})
.then(function (response) {
return response.data;
});
}
};
return itemsFactory;
}]);
myItemsApp.controller('ItemsController', ['$scope', 'itemsFactory', function($scope, itemsFactory){
var promise = itemsFactory.itemDetails();
promise.then(function (data) {
$scope.itemDetails = data;
console.log(data);
});
}]);
json:
[
{
"$id":"1",
"name":"Test itemName 1",
"themeName":"ASD",
"addressLine1":"18 Banksia Street",
"addressLine2":null,
"suburb":"Heidelberg",
"state":"VIC",
"postalCode":"3084",
"contactPhone":"+61 3 123456",
"emailAddress":"qwerty.it#xyz.com"
},
{
"$id":"2",
"name":"Test itemName 2",
"themeName":"WER",
"addressLine1":"11 Riverview Place",
"addressLine2":"Metroplex on Gateway",
"suburb":"Murarrie",
"state":"QLD",
"postalCode":"4172",
"contactPhone":"1300 73123456",
"emailAddress":"asdfg.it#xyz.com"
},
{
"$id":"3",
"name":"Test itemName 3",
"themeName":"ERT",
"addressLine1":"60 Waterloo Road",
"addressLine2":null,
"suburb":"North Ryde",
"state":"NSW",
"postalCode":"2113",
"contactPhone":"123456",
"emailAddress":"zxcvb.it#xyz.com"
}
]
Any help would be greatly appreciated.
I am very new to programming. Please also feel free to alternative ways of achieving this if I have done it wrong.

You can use the ng-click directive to specify what happens when you click something.
So I made it assign the clicked item to the $scope.selected object using a function ($scope.select(item)) and then I bound the properties of that object to your little details section. That's probably the simplest way to do it.
Ctrl
$scope.select = function(item) {
$scope.selected = item;
}
$scope.selected = {};
HTML
<a class="list-group-item" ng-click="select(item)" ng-repeat="item in itemDetails">
{{item.name}}
</a>
And the selected object is then available like this:
<h2>Name: {{selected.name}}</h2>
etc...
See my example here: http://plnkr.co/edit/mUMZ0VGO8l1ufV1JJNQE?p=preview

Related

Show/hide template URL's in angularjs

I have a dynamic Array in Controller which has templates(html files) similar to below
$scope.templates =
[ { name: 'template1.html', url: 'template1.html'},
{ name: 'template2.html', url: 'template2.html'} ];
I have a dropdown to choose the template.
I am using ng-include in html to get these files.
The issue is:
When I have loaded template1.html and then switching to template2.html, I want to hide template1.html data and show template2.html.
The next time, when I select template1.html, I want to hide template2.html data and show template1.html data instead of loading template1.html again.
I have tried below:
html:
<div ng-controller="ExampleController">
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
url of the template: <code>{{template.url}}</code>
<hr/>
<div class="slide-animate-container" ng-show="template.isHidden">
<div class="slide-animate" ng-include="template.url"></div>
</div>
<div class="slide-animate-container" ng-hide="template.isHidden">
<div class="slide-animate"></div>
</div>
</div>
app.controller('ExampleController', ['$scope', function($scope) {
$scope.templates =
[ { name: 'template1.html', url: 'template1.html'},
{ name: 'template2.html', url: 'template2.html'} ];
$scope.template = $scope.templates[0];
$scope.$watch('template',function(newValue, oldValue) {
$scope.templates[0].isHidden = true;//will do _.each to update
$scope.templates[1].isHidden = true;
var xyz = $scope.template;
xyz.isHidden = false;
});
}]);
template1.html, template2.html can be normal html files.
Please suggest.
https://plnkr.co/edit/TJKYbDrp1C1g4fQNHCi2?p=preview
This line:
<div class="slide-animate-container" ng-show="template.isHidden">
prob. meant to be:
<div class="slide-animate-container" ng-include="template.url" ng-show="!template.isHidden">
You want to show the div if the value of isHidden is false.

AngularJS data model architecture

I have the following thing on my Angular app:
$scope.things = [{
title: 'Simple',
type: 1,
form: {
input: [1, 2, 3],
clone: true
}
}];
$scope.clone = function(item) {
item.form.input.push(Math.floor(Math.random() * 999));
};
And on the HTML part:
<div ng-repeat="item in things" class="item">
<h2>{{item.title}}</h2>
<div ng-repeat="input in item.form.input">
<input type="text" />
</div>
<button ng-click="cloneInput(item)">Clone</button>
</div>
When press the Clone button I'm pushing a new element to form.input array and add a new input to the DOM.
I want to $http.post all the values for the inputs.
I know to push something I need to use
$http.post('/path/to/my/api', {my object}).callback()
But I dont know how to make an object from all the .item inputs.
Can someone explain me how or suggest a better solution?
If you use a ng-model for your inputs and set it to an object you can then inject that object to the post, here is a really basic example:
JSFiddle
HTML:
<div ng-app="myApp" ng-controller="dummy">
<div ng-repeat="input in items">
<input type="text" name="{{input.name}}" ng-model="data[input.name]" />
</div>
<button ng-click="submit()">Submit</button>
<p ng-show="displayIt">{{data}}</p>
</div>
JS:
angular.module('myApp', [])
.controller('dummy', ['$scope', function ($scope) {
$scope.items = [{
name: 'test'
}, {
name: 'test2'
}];
$scope.data = {};
$scope.displayIt = false;
$scope.submit = function () {
// This is only to check it
$scope.displayIt = true;
// Do your post here
};
}]);

Selecting a single object from an array to display in a view [Angular]

I've similarly asked this before, but neither solution proved useful.
I currently have a store app built with AngularJS, my problem is, I need to be able to click on one item and open into the "item" view and display only the information with a matching ID from the items array stored in a services.
For example. Item one displayed on store view has an id of 1, and on the store displays the product name etc. When clicked, the item is opened with the item view to display just that product and it's information.
Here's my store Controller:
'use strict';
angular.module('angularStoreApp')
.controller('storeCtrl', function($scope, StoreService){
$scope.items = StoreService.items();
});
Services (Shortened to save spare, there's 12 other items).
'use strict';
angular.module('angularStoreApp')
.service("StoreService", function() {
var items = [ {
itemId: 1,
qty: 0,
stock: 5,
price: 99.00,
name: 'Almond Toe Court Shoes, Patent Black',
category: 'Womens Footerwear'
},
{
qty: 0,
stock: 4,
price: 42.00,
name: 'Suede Shoes, Blue',
category: 'Womens Footerwear'
}];
this.items = function() {
return items;
};
});
Store View
<!-- Start of item iteration -->
<div ng-repeat="item in items">
<!-- Start of item -->
<div class="item">
<div class="item_info">
<img src="http://i.imgur.com/Bn1iB6X.jpg"/>
<div class="item_footer">
<div class="info_text">
<h2>{{item.name| limitTo: 8}}...</h2>
<span>{{item.price | currency}}</span>
</div>
<div class="icon">
<a ng-href="#"><button role="button">More</button></a>
</div>
</div>
</div>
</div>
<!-- End of item -->
</div>
<!-- End of item iteration-->
Item Ctrl
'use strict';
angular.module('angularStoreApp')
.controller('itemCtrl', function ($scope, StoreService) {
$scope.items = StoreService.items();
});
Item View
<div ng-include="'components/navbar/navbar.html'"></div>
<div ng-repreat="item in items">
<div class="item-page-container">
<div class="item-p-img">
{{item.name}}
</div>
<div class="item-p-tab-Container">
<ul>
<li>{{item.name}}</li>
<li></li>
<li></li>
</ul>
</div>
</div>
</div>
Please ask for any more code or for easier view, see my Github Repo
Please be clear on the function, feel free to put into a plunker, my Javascript skills come from Angular, but searching an array like this I haven't done before. I'd need a good solution where I can transfer/learn the logic.
Store View
(not sure about your routing) but would try smt like this:
<a ng-href="/items/{{item.itemID}}"><button role="button">More</button></a>
this should send you to your item view.
In your Item ctrl, if you inject $routeParams you could fetch the id like so:
item_id = $routeParams.id
and then search for your item like so:
items = StoreService.items();
$scope.item = items.indexOf(item_id)
so in your item view remove the ng-repeat and work with the item object.
As I said before, not enterily sure of your project's structures,. but this should get you on your way.
Make your routes like this :
$routeProvider
.when('/items', {
templateUrl: 'yourtemplate-path/items.html',
controller: 'yourItemController'
})
.when('/items/:itemId', {
templateUrl: 'yourtemplate-path/items-detail.html',
controller: 'yourItemDetailsController'
})
Your controller:
For items,
'use strict';
angular.module('angularStoreApp')
.controller('storeCtrl', function($scope, StoreService){
StoreService.items(function(){
$scope.items = data;
});
});
For item detail page,
'use strict';
angular.module('angularStoreApp')
.controller('storeDetailsCtrl', function($scope, $routeParams, StoreService){
StoreService.items({itemId: $routeParams.itemId}, function(){
$scope.item = data;
});
});
and create your new service, which fetches the data based on this id(itemId)
NOTE: I didn't tested the code.

angular.js template variables to bootbox dialog?

I've been trying to figure this out for like 10 hours now. Time to ask for help!
I'm trying to pass a variable from an angular.js template variable to bootbox for a nice looking confirmation prompt.
Assume that I have the following (abbreviated for clarity):
<script>
$(document).on("click", ".confirm", (function(e) {
e.preventDefault();
bootbox.confirm("This needs to be the value of {{item.name}}", function(confirmed) {
console.log("Confirmed: "+confirmed);
});
}));
</script>
which is executed as such:
<ul class="list-group">
<li ng-repeat="item in items">
<span class="glyphicon glyphicon-fire red"></span>
</li>
</ul>
When the user clicks the link, I would like a the confirmation box to appear, and I need to include attributes like {{item.name}} and {{item.row}} that are specific to this element in the list.
I have read up on the $compile functionality of angular.js and I got it working in so far as having a <div compile="name"> but that doesn't help me for retrieving a single entry out of my list as I am iterating. Any help would be appreciated!
Applied as a directive...
HTML:
<body ng-app="myApp" ng-controller="MainController">
<ul class="list-group">
<li ng-repeat="item in items">
<confirm-button name="{{item.name}}"></confirm-button>
</li>
</ul>
</body>
JS:
angular.module('myApp', [])
.controller('MainController', function($scope) {
$scope.items = [
{ name: 'one' },
{ name: 'two' },
{ name: 'three' }
];
})
.directive('confirmButton', function(){
return {
restrict: 'E',
scope: { name: '#' },
template: '<span class="glyphicon glyphicon-fire red" ng-click="confirm(name)">Button</span>',
controller: function($scope) {
$scope.confirm = function(name) {
bootbox.confirm("The name from $scope.items for this item is: " + name, function(result){
if (result) {
console.log('Confirmed!');
} else {
console.log('Cancelled');
}
});
};
}
}
});
Working plunk
This is a simple approach, but depending on what you're trying to do it may not suit you:
var app = angular.module('app', []);
app.controller('AppCtrl', function ($scope) {
$scope.items = [
{ name: "Bla bla bla bla?", url: "http://stackoverflow.com" },
{ name: "Ble ble ble ble?", url: "http://github.com" }
];
$scope.confirm = function (item) {
bootbox.confirm("Confirm?", function (confirmed) {
alert('Confirmed: '+ confirmed +'. Url: '+ item.url);
});
};
});
In your html:
<div ng-app='app' ng-controller="AppCtrl">
<ul class="list-group">
<li ng-repeat="item in items">
<a ng-click="confirm(item)">
<span class="glyphicon glyphicon-fire red"></span>
{{ item.name }}
</a>
</li>
</ul>
</div>
Depending on what you want, maybe you should check out the directives: https://docs.angularjs.org/guide/directive

AngularJS multiple uses of Controller and rootScope

I want to use a controller on 2 seperated HTML elements, and use the $rootScope to keep the 2 lists in sync when one is edited:
HTML
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
<div ng-controller="Menu">
<input type="text" id="newItem" value="" />
<input type="submit" ng-click="addItem()" />
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
</div>
JS
angular.module('menuApp', ['menuServices']).
run(function($rootScope){
$rootScope.menu = [];
});
angular.module('menuServices', ['ngResource']).
factory('MenuData', function ($resource) {
return $resource(
'/tool/menu.cfc',
{
returnFormat: 'json'
},
{
getMenu: {
method: 'GET',
params: {method: 'getMenu'}
},
addItem: {
method: 'GET',
params: {method: 'addItem'}
}
}
);
});
function Menu($scope, MenuData) {
// attempt to add new item
$scope.addNewItem = function(){
var thisItem = $('#newItem').val();
MenuData.addItem({item: thisItem},function(data){
$scope.updateMenu();
});
}
$scope.updateMenu = function() {
MenuData.getMenu({},function(data){
$scope.menu = data.MENU;
});
}
// get menu data
$scope.updateMenu();
}
When the page loads, both the UL and the DIV display the correct contents from the database, but when i use the addNewItem() method only the DIV gets updated.
Is there a better way to structure my logic, or can I do something to make sure the $scope.menu in the UL gets updated at the same time?
Here's an example of something similar: http://plnkr.co/edit/2a55gq
I would suggest to use a service that holds the menu and its methods. The service will update the menu which is referenced by the controller(s).
See a working plunker here: http://plnkr.co/edit/Bzjruq
This is the sample JavaScript code:
angular
.module( 'sampleApp', [] )
.service( 'MenuService', [ '$rootScope', function( $rootScope ) {
return {
menu: [ 'item 1' ],
add: function( item ) {
this.menu.push( item );
}
};
}])
.controller( 'ControllerA', [ 'MenuService', '$scope', function( MenuService, $scope ) {
$scope.menu = MenuService.menu;
$scope.addItem = function() {
MenuService.add( $scope.newItem );
};
}]);
And the sample Html page:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="sampleApp">
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
<input type="text" ng-model="newItem" /><input type="submit" ng-click="addItem()" />
</div>
<div ng-controller="ControllerA">
<ul>
<li ng-repeat="item in menu">{{item}}</li>
</ul>
</div>
</body>
</html>
Edit:
Here is the updated version plunker. it works in two controller.
Main idea is using service and broadcast to sync the data with the directive.
app.service('syncSRV', function ($rootScope) {
"use strict";
this.sync = function (data) {
this.syncData = data;
$rootScope.$broadcast('updated');
};
});
app.controller('MainCtrl1', ['$scope', function ($scope) {
}])
.controller('MainCtrl2', ['$scope', function ($scope) {
}]);
app.directive('sync',function (syncSRV) {
"use strict";
return {
template: '<div><input ng-model="syncdata" type="text" /></div> ',
controller: function ($scope, $element, $attrs) {
$scope.$watch('syncdata', function (newVal, oldVal, $scope) {
syncSRV.sync(newVal);
}, true);
}
};
}).directive('dataview', function (syncSRV) {
"use strict";
return {
template: '<div>Sync data : {{data}}</div> ',
controller: function ($scope, $element, $attrs) {
$scope.$on('updated', function () {
$scope.data = syncSRV.syncData;
});
}
};
});
<div ng-controller="MainCtrl1">
<fieldset>
<legend> Controller 1</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
<div ng-controller="MainCtrl2">
<fieldset>
<legend> Controller 2</legend>
<div dataview></div>
<div sync></div>
</fieldset>
</div>
Here is what I would do for this case.
I will create a directive for
<ul class="nav" ng-controller="Menu">
<li ng-repeat="item in menu">
{{item.title}}
</li>
</ul>
so once item is updated, it will be updated in both directive.
small example
I just want to update and simplify the selected answer. It seems you can reduce this by deleting this line:
$rootScope.$broadcast( 'MenuService.update', this.menu );
and this chunk:
$scope.$on( 'MenuService.update', function( event, menu ) {
$scope.menu = menu;
});
The reason being, we are already using a Service, and that basically binds the two identical controllers, so no need to use $rootScope.$broadcast and add an observable.
Working plunk here:
http://plnkr.co/edit/1efEwU?p=preview
You only need to link the service, when I refactor the code I was able to reduce it to 13 lines instead of 22.

Categories

Resources