Angular create dynamic scope in controller(js) & bind in view(html) - angularjs

I have created this plnkr to show what I'v tried.
$scope.myArray = [{
"productDetails": {
"productName": "productname1",
"qty": 5,
"pricePerPiece": 20
},
"vehiclecategory": "abcd"
},
...
]
Need to bind the values of each vehicle category for each record.
Have two records per row with Label & it's value that will be bind from key vehiclecategory for each object.
Label will remain as it is since its text will change depending upon internationalization, so it will be a constant that will be coming from properties file as per user location. There will be separate constants file for each location.
Currently have hard code the label value. Need to achieve below sample
(1)First Record : abcd1
(2)Second Record : abcd2

#JohnD answer is correct, you can display the item inside an array using ngRepeat but if you want to add ordinal numbers you can have a look in this post "Add st, nd, rd and th (ordinal) suffix to a number"

case 1 )
http://plnkr.co/edit/sA85huMV3nYUJME8tSVx?p=preview
you know the name of label property in your data (the key)
<div class="width50" ng-repeat="item in myArray track by $index">
<label>{{item.label}} - {{$index}}</label> : {{item.vehiclecategory}}
</div>
Javascript :
I added a label attribute to your $scope.myArray.
As JohnD explain, you have to use ng-repeat to iterate over an array and not use "$scope.first, $scope.second ..." (imagine if you have 100)
$scope.myArray = [{
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd1",
"label" : "My Data",
}, {
"productDetails": {
"productName": "productname1", "qty": 5, "pricePerPiece": 20
},
"vehiclecategory": "abcd2",
"label" : "Your Info",
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd3",
"label":"adresse"
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd4",
"label": "street"
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd5",
"label" : "city",
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd6",
"label":"etc"
}];
case 2 )
Maybe the name of the label attribute is not always the same like this :
$scope.myArray = [
{
"productDetails": { "productName": "productname1","qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd1",
"My Data" : "My Data",
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd2",
"Your Info" : "Your Info",
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd3",
"label":"adresse"
}, {
"productDetails": { "productName": "productname1", "qty": 5, "pricePerPiece": 20 },
"vehiclecategory": "abcd4",
"street": "street"
},
...
];
// this array contain all the possible label name
var listoflabel = ["etc","adresse","city","street","Your Info","My Data"];
// search on item if a label key exist and return its value
$scope.getLabel = function(item){
for(var l in listoflabel){
if(item[ listoflabel[l] ]){
return item[ listoflabel[l] ];
}
}
return "label";
}
HTML with function call
<div class="width50" ng-repeat="item in myArrayVariable track by $index">
<label>{{getLabel(item)}}</label> : {{item.vehiclecategory}}
</div>

I'm not sure I completely understand your question, but if I do, you might be able to solve it with ngRepeat. Check out the following example:
<div class="width50" ng-repeat="item in myArray track by $index">
<label>({{$index}}) {{item.vehiclecategory}}</label> : {{item.productDetails.productName}}
</div>

Related

Angular *ngFor: Display only unique property "category" value and lowest price in each "category"

I have an array with objects having "category" & "price" properties among others, in the Angular application I need to display only unique values of "category" property (Example: Economy, Premium & Deluxe) along with the lowest price in that category. I tried filtering it but was unable to achieve it. So can you please help how this can be achieved in Angular? Thank you.
In this example, I need to show:
Economy - Starts from 250USD
Premium - Starts from 400USD
Deluxe - Starts from 600USD
"hotelRooms": [
{
"price": {
"total": 250,
"currency": "USD"
},
"category": "Economy",
"subcategory": "single",
},
{
"price": {
"total": 350,
"currency": "USD"
},
"category": "Economy",
"subcategory": "double",
},
{
"price": {
"total": 450,
"currency": "USD"
},
"category": "Economy",
"subcategory": "family",
},
{
"price": {
"total": 400,
"currency": "USD"
},
"category": "Premium",
"subcategory": "single",
},
{
"price": {
"total": 500,
"currency": "USD"
},
"category": "Premium",
"subcategory": "double",
},
{
"price": {
"total": 600,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "single",
},
{
"price": {
"total": 700,
"currency": "USD"
},
"category": "Deluxe",
"subcategory": "double",
}
]
And in Angular:
<div *ngFor="let room of hotelRooms">
<span class="bold">{{ room.category }}</span> - Starts from {{ room.price.total}}{{ room.price.currency}}
</div>
From what I understand on this question, you need to group by category and next get the lowest price.amount for each category.
Concept (TL;DR)
Group By Category
1.1 Create an array for each category if the category array does not exist. Else reuse the created category array.
1.2 From each category array, find the lowest record based on price.amount.
1.3 If the result (from 1.2) return no value (undefined), first reset category array to empty array and add the current record to the category array. This ensures that each category will only have 1 record with the lowest price. Else just ignore it.
Data Transformation
2.1 Get the item from each category via iterate with key. It will return arrays.
2.2 Concat multiple arrays (from 2.1) into one array.
let groupByCategories = [];
groupByCategories = this.hotelRooms.reduce(function (previous, current) {
previous[current.category] = previous[current.category] || [];
let lowest = previous[current.category].find(
(x) =>
x.price.total < current.price.total
);
if (!lowest) {
previous[current.category] = [];
previous[current.category].push(current);
}
return previous;
}, Object.create(null));
this.hotelRooms = [].concat(
...Object.keys(groupByCategories).map((key) => {
return groupByCategories[key];
})
);
Sample Demo on StackBlitz

rxjs/Angular2 Loop but show different object of a single associative array

I recently combined two array using rxjs
MyArray = [{
"Field": ["Cars"],
"Type": ["BMW", "Toyota", "Volvo"]
},
{
"Field": ["House"],
"Type": ["Condominium", "TownHouse"],
}
PriceArray = [
{
field: Cars,
distribution: [{"name" : "BMW","price":2},{"name" : "Toyota","price":3}]
},
{
field: People,
distribution: [{"name" : "Condominium","price":3},{"name" : "TownHouse","price":2}]
}]
using rxjs filter
const $MergeData = MyArray.map(val => {
return Object.assign({}, val,this.PriceArray.filter(v => v.Field === val.field)[0])
});
this.mergedArray = $MergeData;
Now it looked this..
mergedArray = [{
"Field": "Cars",
"Type": ["BMW", "Toyota", "Volvo"],
"field" : "Cars",
"distribution" : [
{
"name" : "BMW"
"price": 2 ,
},
{
"name" : "Toyota"
"price": 3 ,
},
{
"name" : "Toyota"
"price": 4 ,
}
]
}, .... (house array here)];
Then I tried to show the item price but its not working
<div *ngFor="let item of mergedArray">
<div *ngFor="let car of item.Field; let i = index">
<p>{{car}} </p>
<p>{{item.distribution.price[i]}} </p>
</div>
</div>
I am hoping for a fix or better if the array should look like this instead
mergedArray = [{
"Field": "Cars",
"Type": ["BMW": 2, "Toyota" : 3, "Volvo" : 4],
}]
Hoping it would me possible as it is much easier to loop.
I think that this is the desired effect, also keep in mind that when using Array.prototype.filter and no elements pass the test the returned value will be [] and if you try to access the [][0] element, the value will be undefined, after that if you try to access some property from that undefined value, it will throw an error.
For example if you try to access the price of Volvo it will throw an error Cannot read property 'price' of undefined, because Volvo doesn't exist in the PriceArray
let priceArray = [
{
"name" : "BMW",
"price": 2
},
{
"name" : "Toyota",
"price": 3
},
{
"name" : "Toyota",
"price": 4
}
];
let myArray = [{
"Field": "Cars",
"Type": ["BMW", "Toyota", "Volvo"]}]
let findPrice= (priceArray,mark)=> priceArray
.find(x=> x.name === mark)
? priceArray.find(x=> x.name === mark).price
: 'No data'
let mergedArray = myArray[0].Type.map(x=> ({[x]:findPrice(priceArray,x)}))
console.log(mergedArray)

Dynamic form using AngularJS, multiple values binding

I am looking for a best approach to convert a static form to an angular dynamic form. I am not sure how to bind multiple values to the same answer.
The static page is available at: https://jsfiddle.net/hvuq5h46/
<div ng-repeat="i in items">
<select ng-model="i.answer" ng-options="o.id as o.title for o in i.answersAvailable" ng-visible="y.TYPE = 'SINGLE'"></select>
<input type="checkbox" ng-model="i.answer" ng-visible="y.TYPE = 'MULTIPLE'" />
</div>
The JSON file
[
{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [
{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [
{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
Things would be much simpler if you can use a multiple select, but I understand it might be difficult for user to interact (consider something like md-select, which transforms multiple select into a list of checkbox for you)
Multiple select:
<select multiple
ng-model="i.answer"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"></select>
Anyway it is completely ok to use HTML checkbox. To do that we would need to bind checkbox model into the data as usual, and then update the answer array simultaneously.
ng-model="o.selected"
ng-change="updateAnswer(i)"
Also, we'll need to copy existing data to model during init.
ng-init="initMultiple(i)"
Working code:
angular.module('test', []).controller('Test', Test);
function Test($scope) {
$scope.items = [{
"id": 1,
"title": "Are you a student?",
"type": "SINGLE",
"answersAvailable": [{
"id": 1,
"title": "Yes"
},
{
"id": 2,
"title": "No"
}
],
"answer": [
1
]
},
{
"id": 2,
"title": "Would you like to be an astronaut?",
"type": "SINGLE",
"answersAvailable": [{
"id": 4,
"title": "Yes"
},
{
"id": 5,
"title": "No"
},
{
"id": 6,
"title": "I am not sure"
}
],
"answer": [
4
]
},
{
"id": 3,
"title": "What is your favourite planet?",
"type": "MULTIPLE",
"answersAvailable": [{
"id": 7,
"title": "Earth"
},
{
"id": 8,
"title": "Mars"
},
{
"id": 9,
"title": "Jupiter"
}
],
"answer": [
7,
8
]
}
]
$scope.initMultiple = function(item) {
item.answersAvailable.forEach(function(option) {
option.selected = item.answer.indexOf(option.id) != -1;
});
}
$scope.updateAnswer = function(item) {
item.answer = item.answersAvailable.filter(function(option) {
return option.selected;
})
.map(function(option) {
return option.id;
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app='test' ng-controller='Test'>
<div ng-repeat="i in items">
<select ng-model="i.answer[0]"
ng-options="o.id as o.title for o in i.answersAvailable"
ng-if="i.type == 'SINGLE'"></select>
<label ng-repeat="o in i.answersAvailable"
ng-if="i.type == 'MULTIPLE'"
ng-init="initMultiple(i)">
<input type="checkbox"
ng-model="o.selected"
ng-change="updateAnswer(i)" /> {{o.title}}
</label>
<div>{{i.answer}}</div>
</div>
</div>
Based on my experience, I will make a separation as two Angular models (or usually called services) for the form questions and another one which will collect the answers and eventually will be passed to the backend for further processing. This will provide me a flexibility to maintain both logic and presentation.
var myModule = angular.module('myModule', []);
myModule.factory('QuestionsFormService', function() {
var _question1;
var _question2;
var _question3;
function init(data){
//questions initiation
}
return init;
});
var myModule = angular.module('myModule', []);
myModule.factory('FormDataService', function() {
var _dataAnswer = {}
function init(){
//data initialization
}
function insertData(key, value){
_dataAnswer[key] = value
}
return init;
});
From the example of service models above, you need to make these available to your presentation through the Angular controller with Dependency Injection.
myModule.controller("MyCtrl", function($scope, FormDataService, QuestionsFormService) {
$scope.form_questions = QuestionsFormService.init();
$scope.form_answers = FormDataService.init()
//further logic to make these available on your view on your convenience
});
What you write on the HTML page as an Angular view is already close enough. You only need to change the binding to two models as I propose above. Thank you.

How can I change the attribute in dataset of Fusionchart?

Hi I am implementing a chart in my Angularjs Application, You can see this plunker http://jsfiddle.net/fusioncharts/73xgmacm/ The thing which I want to achieve is to change the value attribute to profit. How can I do this ? I want to display profit not values.
Regards
After 2 days I finally find out the answer. The thing is You cannot change the Fusionchart attribute value but you can change the attribute of your API once you fetched. I used a loop after I fetched the API and replace the 'profit' attribute with value in this way I made the chart. Yes The thing which i had been ignoring was the use of 'variable' instead of scope. If you see this example you would understand Example Here. I am sharing my code May be it helps someone else too.
Give below is my json array which i called tps.json
[
{
"index": "1",
"variantoption": "fan-green",
"company": "sk fans",
"quantity": "650",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "2",
"variantoption": "fan-white",
"company": "al ahmed fans",
"quantity": "450",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "3",
"variantoption": "fan-purple",
"company": "asia fans",
"quantity": "350",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "4",
"variantoption": "fan-yellow",
"company": "falcon fans",
"quantity": "250",
"profit": "78296",
"loss": "8457",
"year": "2016"
}
]
and here is my controller
$http.get('js/tps.json').success(function (data) {
var chartdata = data;
var arrLength = chartdata.length;
console.log(arrLength);
for (var i = 0; i < arrLength; i++) {
if (chartdata[i]['profit'] && chartdata[i]['index']) {
chartdata[i].value = chartdata[i].profit;
delete chartdata[i].profit;
chartdata[i].label = chartdata[i].index;
delete chartdata[i].index;
console.log(chartdata);
}
}
console.log(chartdata);
FusionCharts.ready(function () {
var tps = new FusionCharts({
type: 'column2d',
renderAt: 'chart-container',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Monthly",
"xaxisname": "Month",
"yaxisname": "Revenue",
"numberprefix": "$",
"showvalues": "1",
"animation": "1"
},
"data" : chartdata
}
});
tps.render();
});
}
);
}
-Stay foolish stay hungry

Ng-option directive cant get access to nested array value

Help
I'm trying to output different class options(economy/business) with ng-options.
Here is the syntax and json information .
Cant get it working
<select ng-model="mySelect" ng-options="item for item in items ">
</select>
$scope.items = [
{
"id": 2,
"codeName": "class",
"friendlyName": "Class",
"options":
[
{
"id": 15,
"displayOrderNo": 0,
"optionName": "Economy"
},
{
"id": 16,
"displayOrderNo": 1,
"optionName": "Business"
},
{
"id": 36,
"displayOrderNo": 2,
"optionName": "First Class "
}
]
}
];

Resources