Angular ng-repeat inside ng-repeat collapse - javascript

I have been attempting to perform an ng-repeat inside an ng-repeat collapse. My inner ng-repeat, repeats the entire array inside of every div. I have tried to track by index but still no resolve:
<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div ng-repeat="s in stuff" >
<p>{{s.$$state.value.Address}}</p>
<p>{{s.$$state.value.GoogleLink}}</p>
<p>{{s.$$state.value.Products}}</p>
<p>{{s.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
Inside Controller:
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
$scope.marketInfo = [];
$scope.getInfo = function(){
return $scope.marketInfo;
}
for(var property in $scope.marketResults) {
var id = $scope.marketResults[property].id;
console.log(id);
$scope.marketInfo.push(getDetails(id));// brings back the details
};
console.log($scope.getInfo());
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},

You need to add the second array as a property of each item in first array. See below code:
HTML:
Instead of writing ng-repeat = "s in stuff", we will write ng-repeat = "s in m.stuff"
<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div ng-repeat="s in m.stuff" >
<p>{{s.$$state.value.Address}}</p>
<p>{{s.$$state.value.GoogleLink}}</p>
<p>{{s.$$state.value.Products}}</p>
<p>{{s.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
Controller:
First load marketResults array. Then in for loop, loop through each element in marketResults and load the second array using id and save it as stuff property for each element, so we can access second array using m.stuff in ng-repeat
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
for(var market in $scope.marketResults) {
market.stuff = getDetails(market.id);// brings back the details
};
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},

You can use ng-init to keep children on each parent row. Pass id to a getChild(m.id) and get child and then use it on second loop.
ng-init="rowchild = getChild(m.id)"
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5" ng-init="rowchild = getChild(m.id)">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">
{{m.marketname}}
</div>
<div uib-collapse="m.isCollapsed">
<div ng-repeat="s in rowchild">
<p>{{s.Address}}</p>
</div>
</div>
</div>
</div>

<div class="col-md-4">
<div id="markets">
<div class="panel panel-default" ng-repeat="m in marketResults | limitTo:5">
<div class="panel-heading" ng-click="m.isCollapsed = !m.isCollapsed">{{m.marketname}}
</div>
<div uib-collapse="!m.isCollapsed">
<div>
<p>{{m.stuff.$$state.value.Address}}</p>
<p>{{m.stuff.$$state.value.GoogleLink}}</p>
<p>{{m.stuff.$$state.value.Products}}</p>
<p>{{m.stuff.$$state.value.Schedule}}</p>
</div>
</div>
</div>
</div>
</div>
//Inside Controller
_getLocation: function(key) { //extract latlng from _recordsCache
var latLong = this._recordsCache[key];
// console.log(latLong);
fmCoordinates.lat = latLong.lat;
fmCoordinates.lng = latLong.lng;
var promise = requestMarkets(fmCoordinates.lat,fmCoordinates.lng);
promise.then(function(marketData) {
$scope.marketResults = marketData.results; //receiving market data
$scope.quantity = 5; //limit market data to 5
$scope.marketInfo = [];
console.log($scope.marketResults);
for (var i = 0; i < marketData.results.length; i++){
marketData.results[i].stuff = getDetails(marketData.results[i].id);
};
}, function(reason) {
console.log('Failed: ' + reason);
});
if( this._recordsCache.hasOwnProperty(key) )
return latLong;//then after use .loc attribute
else
return false;
},

Related

AngularJS Html not updating with data change from factory

I started with this simple plunkr
From what I can tell it only uses one component. I have a project that uses multiple components. I have a cart and users clicks add button to add items to said cart. The check out component just empties the cart. I expect that when the cart is empty, the display also empties and the total would show 0.00, but that is not happening. From what I can tell the HTML only changes page load not on change of data and that is the problem, but it was my understanding that angular would take care of this on its own.
Thanks in advance
Relevant code:
app.config.js (this file has the factory and checkout functionality)
'use strict';
angular.
module('floorForceApp').
config(['$routeProvider', '$provide',
function config($routeProvider,$provide) {
$routeProvider.
when('/home', {
template: '<home-page></home-page>'
}).
when('/floors', {
template: '<floor-page></floor-page>'
}).
when('/cabinets', {
template: '<cabinet-page></cabinet-page>'
}).
when('/walls', {
template: '<wall-page></wall-page>'
}).
when('/checkout', {
template: '<checkout-page></checkout-page>'
}).
otherwise('/home');
},
]).factory('floorForceCart',function(){
let total = 0;
let addedItems = [];
// let additem = function(item,price){
// }
return{
addItems:function(item,count){
let exist =false;
$.each(addedItems,function(i,v){
if(v.itemNo === item.itemNo){
exist = true;
v.count = v.count + count;
total = total + (item.itemPrice*count);
}
});
if(!exist){
let toPush = {};
toPush.itemNo = item.itemNo;
toPush.count = count;
toPush.itemName = item.itemName;
toPush.itemPrice = item.itemPrice;
addedItems.push(toPush);
total = total + (item.itemPrice*count);
}
console.log("Cart:",addedItems);
console.log("Total:",total);
},
removeItems: function(item,count){
$.each(addedItems,function(i,v){
if(v.itemNo === item.itemNo){
v.count = v.count - count;
total = total - (item.itemPrice * count);
if(v.count == 0){
addedItems.splice(i,0);
}
}
});
},
getTotal:function(){
return total;
},
getCart:function(){
return addedItems;
},
checkout:function(){
total = 0;
addedItems = [];
console.log("Check out successful.");
console.log("Total:",total,"Cart:",addedItems);
alert("Checkout Successful!");
}
};
});
checkout-page.component.js (data is loaded from factory to here)
'use strict';
angular.
module('checkoutPage').
component('checkoutPage',{
templateUrl: 'checkout-page/checkout-page.template.html',
controller: function checkOutController($scope,$http,floorForceCart){
let self = this;
$scope.total = floorForceCart.getTotal();
$scope.cart = floorForceCart.getCart();
$scope.checkOut = function(){
floorForceCart.checkout();
}
}
})
checkout-page.html (this page displays the checkout)
<div>
<div style="height:30em;">
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-4 h-100 ">
<div class="row prodImage h-100"></div>
</div>
<div class="col-sm-8 h-100 ">
<div class="row h-100">
<div class="checkOutTitleDiv titleDiv">Checkout</div>
<div class="checkOutCartDiv paddingZero">
<div ng-repeat="item in cart" class="row marginAuto cartItemRow">
<div class="itemNameDiv col-sm-5">{{item.itemName}}</div>
<div class="itemPriceDiv col-sm-3">{{item.itemPrice|currency}}</div>
<div class="itemQuantityDiv col-sm-4">
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-4 itemQuantity">{{item.count}}</div>
<div class="col-sm-4"></div>
</div>
</div>
</div>
</div>
<div class="checkOutButtonDiv paddingZero">
<div class="row h-100 marginAuto">
<div class="col-sm-4 cartTotalDiv">
<div class="">Total:{{total|currency}}</div>
</div>
<div class="col-sm-4"></div>
<div class="col-sm-4">
<input class="checkOutButton btn btn-success" ng-click="checkOut()" type="button"value="Check Out"/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
It is because in the controller you add a property in the $scope referencing the same array of items referenced by the addedItems variable in the factory:
$scope.total = floorForceCart.getTotal();
$scope.cart = floorForceCart.getCart();
Then, when you call checkout from the factory, you re-assign the addedItems variable from the factory to a new array, and you assign a 0 to the total variable. The problem is that the properties $scope.total and $scope.cart doesn't have any way of knowing this. $scope.cart will still be pointing to the old array with items.
You could solve this by either:
Changing your $scope.checkOut to
$scope.checkOut = function(){
floorForceCart.checkout();
// And refresh your $scope
$scope.total = floorForceCart.getTotal();
$scope.cart = floorForceCart.getCart();
}
Or by instead of assigning a new array to addedItems in the factory, clearing it using:
addedItems.length = 0;
If you go with the last approach, you would still have to do $scope.total = floorForceCart.getTotal(); after floorForceCart.checkout(); to update the total in your $scope.

How to get the new y-value within gridstack.js

I'm using Gridstack for draggable div's.
How do I get the new value of data-gs-y (so to which y-axis the div was dropped).
Actually I tried this:
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<div class="grid-stack" data-gs-width="12" data-gs-animate="yes">
<div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="12" data-gs-height="1" data-gs-id="facebook">
<div class="grid-stack-item-content">facebook</div>
</div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="1" data-gs-width="12" data-gs-height="1" data-gs-id="workbook">
<div class="grid-stack-item-content">workbook</div>
</div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="2" data-gs-width="12" data-gs-height="1" data-gs-id="pictures">
<div class="grid-stack-item-content">pictures</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function () {
$('.grid-stack').gridstack({
disableResize: true,
removable: true
});
});
$('.grid-stack').on('dragstop', function(event, ui) {
var element = event.target;
var id = $(element).attr('data-gs-id');
var y = $(element).attr('data-gs-y');
alert(id + y);
});
$('.grid-stack').on('dropped', function (event, previousWidget, newWidget) {
alert('dropped'); // It's not thrown
});
$('.grid-stack').on('change', function(event, items) {
var element = items[0].el[0];
var id = $(element).attr('data-gs-id');
var y = $(element).attr('data-gs-y');
alert(id + y);
});
</script>
So the event dragstop and also change is given me the current/old value of the y-axis and the dropped event is not thrown..
How do I get the new value of the y-axis?
I think you can use "mutation observer" to listen changes to the attribute 'data-gs-y' on each div element. I wrote following code and verified on this demo http://gridstackjs.com/demo/knockout.html
var divs = document.querySelectorAll(".grid-stack-item");
var dragging = false;
divs.forEach(function(div){
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if(!dragging){
alert("new y-value " + div.getAttribute("data-gs-y"));
}
});
});
observer.observe(div, { attributes: true, attributeFilter: ['data-gs-y'] });
div.onmousedown = function(){ dragging = true;}
div.onmouseup = function(){ dragging = false;}
});

How to iterate through HTML entities with javascript

I have the following HTML [below]. I am trying to iterate through all DOM with class="gmvcRow", and grab the text in all of the "gmvcCell" for each 'gmvcRow'. I would like to place all the text in an array(['firstname', 'lastname', 'dob', 'city']). And i would like to place this array into another array that holds "arrays of gmvcRow". My attempt is below but i am still not successful. I understand that the text in 'gmvcCell' is in itself another label node.
<div class="gmvcRow">
<div class="gmvcCell">firtname</div>
<div class="gmvcCell">lastname</div>
<div class="gmvcCell">dob</div>
<div class="gmvcCell">city</div>
</div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
my code:
var gmvcRowArray = document.getElementsByClassName('gmvcRow');
console.log('number of records: ' + gmvcRowArray.length);
// Master array
var masterArray = [];
// Iterate through array
for(var i=0; i<gmvcRowArray.length; i++){
// Iterate through all childNodes
var rowArray = [];
for(var c=0; c<gmvcRowArray[i].childNodes.length; c++){
c = c + 1; // skip non text node
console.log('c: '+c);
if(gmvcRowArray[i].childNodes[c] != null){
var value = gmvcRowArray[i].childNodes[c].innerHTML;
rowArray.push(value);
//console.log('rowArray.length: '+rowArray.length);
console.log('value: '+value);
}
c = c - 1;
}
// Add row to master array
masterArray.push(rowArray);
console.log('masterArray.lengh: '+masterArray.length);
}
Using childNodes makes it harder than needed, since it also selects text nodes.
Instead use some of the ES6 features, which lead to concise code:
var arr = Array.from(document.querySelectorAll('.gmvcRow'), row =>
Array.from(row.querySelectorAll('.gmvcCell'), cell => cell.textContent)
);
console.log(arr);
<div class="gmvcRow">
<div class="gmvcCell">firstname</div>
<div class="gmvcCell">lastname</div>
<div class="gmvcCell">dob</div>
<div class="gmvcCell">city</div>
</div>
<div class="gmvcRow">
<div class="gmvcCell">Helene</div>
<div class="gmvcCell">Johnson</div>
<div class="gmvcCell">11/11/1995</div>
<div class="gmvcCell">Paris</div>
</div>
Quick sample for 1-level nesting
var rows = Array.from(document.getElementById('container').querySelectorAll('.gmvcRow'));
const result = rows.map(row => {
return Array
.from(row.querySelectorAll('.gmvcCell'))
.map(cell => cell.innerText);
});
console.log(result);
https://jsfiddle.net/snba2qsf/
After all you can filter result to exclude empty arrays
In your Script: Just check the value before adding to row array whether Is not null and not undefined.
if(value != null || value != undefined)
{
rowArray.push(value.trim());
}
Here is my answer using querySelectorAll
var gmvcRowArray = [];
document.querySelectorAll('.gmvcRow').forEach((el, idxRow) =>{
var gmvcCellArray = [];
el.querySelectorAll('.gmvcCell')
.forEach((el) =>{
gmvcCellArray.push(el.innerText);
});
gmvcRowArray.push(gmvcCellArray)
})
console.log(gmvcRowArray)
<div class="gmvcRow">
<div class="gmvcCell">Name1</div>
<div class="gmvcCell">lastname1</div>
<div class="gmvcCell">dob1</div>
<div class="gmvcCell">city1</div>
</div>
<div class="gmvcRow">
<div class="gmvcCell">Name2</div>
<div class="gmvcCell">lastname2</div>
<div class="gmvcCell">dob2</div>
<div class="gmvcCell">city2</div>
</div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>
<div class="gmvcRow"></div>

Displaying results, in different div's from a JavaScript loop

var parseResponse = function() {
var data = JSON.parse(this.response);
console.log (data);
var head = "Cheapest Flight to " + document.getElementById('search_term1').value;
var bodystuff = document.createElement('h4');
bodystuff.innerHTML = head;
document.getElementById('right1').appendChild(bodystuff);
for (var i=0; i<data.results.length; i++) {
try {
var printDeparture = "Depart: " +
data.results[i].itineraries[i].outbound.flights[i].departs_at;
var bodystuff = document.createElement('p');
bodystuff.innerHTML = printDeparture;
document.getElementById('right1').appendChild(bodystuff);
console.log(printDeparture);
} catch (err) {
console.log(data.results[i]);
}
}
}
I am trying to get each result printed out in a separate div (currently, I have 3 results back) but can only print out the first of the three, I have tried to increase [i] in each of the results, and changed the divs from "right1" to "left1" but nothing happens. any help?
Here is my HTML code;
<div class="wrap">
<div class="left">
<img src="Assets/China.png" class="pics">
</div>
<div class="right" id="right1">
</div>
</div>
<div class="wrap">
<div class="left" id="left1">
</div>
<div class="right" >
<img src="Assets/hotel.jpg" class="pics">
</div>
</div>
and here is the result I get back from the API:
Object
results
:
Array[3]
0
:
Object
1
:
Object
2
:
Object
(hope it makes sense)

append html to the div with AngularJS

How can i pass html through in AngularJS controller ?
Here is my list.html:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" class="col-md-12 listing-div hidden"></div>
in controller.js:
$scope.pData = [];
$scope.getPackageInfo = function(id,name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
if(data != 0) {
$("#lp").html(summery); // this is used to append the data
document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$('#loading').hide();
} else {
document.getElementById("lp").classList.add("hidden");
document.getElementById("np").classList.remove("hidden");
$('#loading').hide();
}
});
};
Here, I have wrote $("#lp").html(summery);, in that div I have to append html which comes from var summery = SubscriptionoptioncompanylistFactory.getSummary(id);. But this is not going to append the data. In console I can see that data comes in summary variable. How can I do?
have a look at below modifications
Use angular ng-show for showing/hiding elements
Use data binding and avoid Jquery like Dom manipulation
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({{item.iCompanyID}},'{{item.vCompanyName}}')" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
<div id="packagehtml"></div>
</div>
<div id="lp" ng-show="lbVisible" class="col-md-12 listing-div hidden">{{summaryBinding}}</div>
and the controller would look like :
$scope.pData = [];
$scope.getPackageInfo = function (id, name) {
$scope.name = name;
var summery = SubscriptionoptioncompanylistFactory.getSummary(id);
$scope.lbVisible = true; //document.getElementById("lp").classList.remove("hidden");
$('.packages-data').html('');
$scope.loadingVisible = true; //$('#loading').show();
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function (data) {
if (data != 0) {
$scope.summaryBinding = summery; // $("#lp").html(summery); // this is used to append the data
$scope.npVisible = false; // document.getElementById("np").classList.add("hidden");
Array.prototype.push.apply($scope.pData, data);
$scope.loadingVisible = false; // $('#loading').hide();
} else {
$scope.lbVisible = false; //document.getElementById("lp").classList.add("hidden");
$scope.npVisible = false; //document.getElementById("np").classList.remove("hidden");
$scope.loadingVisible = false; // $('#loading').hide();
}
});
};
your snippet is not showing elements that you use :
np, #loading so just find them and add the `ng-show` with the proper scope variable : `npVisible , lbVisible , loadingVisible`
and note that we add the data using summaryBinding
hope this helps :)

Categories

Resources