Moltin Cart, Laravel and Angular JS – looping through JS object - javascript

I'm using a Moltin Cart which I want to loop through, so I can read it in Angular JS and then
I load the cart into a variable, which I'd like to <div ng-repeat-start="item in cart.contents"> and loop through the items in the cart.
The issue I'm having is really a pretty basic JavaScript issue, that if I console.log the cart.contents I get this:
Object{
33bb9f991617377b9b8333a79ca9ce2c: Object { ... cart contents... },
1ba14b804d0d81e49397b004e5f1c6d1: Object { ... cart contents... },
33bb9f991617377b9b8333a79ca9ce2c: Object { ... cart contents... },
}
Is there a way that I can fix this either in:
Laravel
Angular JS
or Classic JavaScript

I think what you're trying to do is this:
angular.module('myapp', [])
.controller('MyController', function($scope) {
$scope.objectOfObjects = {
"ASDF": { name: 'First', price: 100 },
"QWER": { name: 'Second', price: 200 },
"FGHJ": { name: 'Third', price: 500 }
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myapp">
<div ng-controller="MyController">
When iterating over an object of objects, there is no guarantee about the order:
<div ng-repeat-start="item in objectOfObjects">{{item.name}}</div>
<div ng-repeat-end>{{item.price}}<br/><br/></div>
</div>
</body>

Related

Problem accessing an array element from json in angular/html

I have the following json data, which comes from mongoDB:
{"list":
[{
"_id":"62f2fabd09de07c09f9e17e2",
"categoryName":"Web development",
"subcategories":[
{
"subcategoryName":"Backend",
"skills":["Nodejs", "Express"]
},
{
"subcategoryName":"Frontend",
"skills":["Css", "SASS"]
}
]
},
{
"_id":"62f33ba62ae52a71daa99a30",
"categoryName":"Cybersecurity",
"subcategories":[
{
"subcategoryName":"Red team",
"skills":["cURL","wfuzz"]
},
{
"subcategoryName":"Blue team",
"skills":["Cloudfare", "Burpsuite"]
}
]
}]
}
This is my angular scope, which gets the json data from the endpoint:
$scope.listSkills = function() {
$http.get("/showSkills").success(function(skills_from_database){
$scope.skills = skills_from_database.list;
})
}
And finally is my html/angular code
<div ng-repeat="category in skills">
<h1>{{category.categoryName}}</h1>
<div ng-repeat="subcategory in category.subcategories">
<hr>
<h2>{{subcategory.subcategoryName}}</h2>
<div ng-repeat="skill in category.subcategories">
<h5>{{skill.skills}}</h5>
</div>
</div>
</div>
The result is:
Category works
Subcategory works, but it gets all skills from the category, not only from the subcategory
Skills doesn't work, it gets the skills section but it should get all the arrays value, which I don't know how to do
Your inner loop needs to iterate over each member of subcategory.skills . I'm not sure why you are iterating again over the same object. (ng-repeat="subcategory in category.subcategories" and ng-repeat="skill in category.subcategories")
<div ng-repeat="skill in subcategory.skills">
{skill}
</div>

show only one column of data of 2D array of scope

I am making a very simple custom directive, which will show, one column of product details, that is present in scope, as 2D array. The custom directive, will have an attribute, that will pass, which column of array has to be shown . Please see following plnkr--
https://plnkr.co/edit/zVIRZ8ADdQB4X8dSFOaJ
From UI I am using this--
<show-products type="name"></show-products>
Currently all data of the array is showing. but i need to show only 1 column of data and that column will be mentioned by directive attribute(for example -name as in plnkr)
In link function I am able to get the column name by using following code-
link: function postlink(scope, element, attr) {
console.log("...type..." + attr["type"]); // prints name
}
but how to pass that field name to template?
template: '<div ng-repeat="x in products">{{x}}</div>' // i need to print only name column here
You get those attributes for the template function as well, just create a function instead of a string and pass your attribute type into the product type variable.
The documentation for the function version of the template can be found in the angular v1 documentation: https://docs.angularjs.org/guide/directive
For more see the snippet below.
<html ng-app="app">
<head>
<title>Directives</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.js"></script>
<script>
angular.module("app", []);
angular.module("app")
.controller("ctrl", ctrl)
.directive("showProducts", showProducts);
function ctrl($scope) {
$scope.products = [{
name: "Apples",
category: "Fruit",
price: 1.20,
expiry: 10
}, {
name: "Bananas",
category: "Fruit",
price: 2.42,
expiry: 7
}, {
name: "Pears",
category: "Fruit",
price: 2.02,
expiry: 6
}];
};
function showProducts() {
return {
template: (child, attributes) => {
return `<div ng-repeat="x in products">{{x["${attributes["type"]}"]}}</div>`
}
};
};
</script>
</head>
<body>
<div class="panel panel-default">
<div class="panel-body" ng-controller="ctrl">
<show-products type="name"></show-products>
</div>
</div>
</body>
</html>

Unable to use inherited/isolated scope concept in my example plunker

I am learning inherited/isolated scopes in angular directives and struck with some basic concepts. please see the plunker below.
Example.
Scenario1:
I have 2 directives (book and details). I am displaying two "Book Details" containers and toggling book name by sending custom attributes like this.
<book bookdetails="book" collapsed="yes" list="list"></book>
<book bookdetails="book1" collapsed="no" list="list"></book>
Question: Is this the right way to handle displaying things in 2 different containers?
Scenario 2:
I want to hide the author details section in container 1 but show in container2 on load. How to accomplish that?
When I use this line below it will hide and show both author details section but I want to keep it separate.
<details collapsed="yes"></details>
I know I am lacking basic skills using inherited/isolated scopes. Can someone educate me?
It's OK to use nested directives like you've used so you can do everything related to the details pane in the details controller like removing items from the books list.
If you wouldn't do any logic in details controller and just include some html I would just use ng-include.
Some points I've detected during improving your code:
Template markups are partial html files, so no need to add header, body etc. Just add your markup that you need in your directive.
I've created one model array books that you can iterate with ng-repeat and not two separate scope variables. That's easier to add more books.
I wouldn't pass the collapsed state to directive isolated scope. I would add it to the book model then you can have independent states of the details panes.
You could also create a collapsed array scope variable separate from your model and use it like ng-hide='collapsed[$index]' if you don't like to add it to your model.
Don't compare to the string yes. It makes things more complicated. It's better to use true or false.
The list you're passing is OK if you'd like to use one list for every details pane. But I think you need them independent from each other so add it to your book model.
For toggeling a value you can use the js shorthand: collapsed = !collapsed;. It takes the value of collapsed and inverts it and re-asigns it to collapsed.
Details directive: You don't need to pass attributes to a directive that doesn't use isolated scope. Instead you can directly use the inherited scope of the parent.
Note: I think you should have a look at angular-ui-bootstrap and use an accordion instead of your manually created panes later. But for learning directives your code is OK.
Please have a look at your updated code below or in this plunker.
If something is not clear, feel free to add a comment and I'll try to help.
angular.module('plunker', [])
.controller('MainCtrl', function($scope) {
$scope.books = [{
id: 0,
name: 'Building modern ASP.NET 5',
author: {
name: 'name1',
age: 31,
country: 'USA'
},
collapsed: false,
list: [{
id: 0,
name: 'book1'
}, {
id: 1,
name: 'book2'
}, {
id: 2,
name: 'book3'
}]
}, {
id: 1,
name: 'AngularJS',
author: {
name: 'name2',
age: 27,
country: 'USA'
},
collapsed: true,
list: [{
id: 0,
name: 'book1'
}, {
id: 1,
name: 'book2'
}, {
id: 2,
name: 'book3'
}]
}];
//$scope.list = ["book1", "book2", "book3"];
}).directive('book', function() {
return {
restrict: 'E',
templateUrl: 'book.html',
scope: {
bkdet: "=bookdetails"
//list: "="
//collapsed: "#"
},
controller: function($scope) {
$scope.toggleDetails = function() {
$scope.bkdet.collapsed = !$scope.bkdet.collapsed;
updateCaption();
};
function updateCaption() {
$scope.hypshowhide = $scope.bkdet.collapsed ? 'show details' : 'hide details';
}
// first run
updateCaption();
/*if ($scope.collapsed == 'yes')
{
$scope.dethide = true;
}
else {
$scope.dethide = false;
} */
//$scope.hypshowhide = 'show details';
}
}
})
.directive('details', function() {
return {
restrict: 'E',
templateUrl: 'details.html',
controller: function($scope) {
/*console.log($scope.bkdet.collapsed);
if (!$scope.bkdet.collapsed) { //== 'yes') {
$scope.dethide = true;
}
else {
$scope.dethide = false;
}*/
$scope.removeItem = function(index) {
$scope.bkdet.list.splice(index, 1);
}
}
}
})
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="plunker">
<div ng-controller="MainCtrl">
<div class="container">
<book bookdetails="book" ng-repeat="book in books"></book>
</div>
</div>
<script type="text/ng-template" id="book.html">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h1>Book Details</h1>
</div>
<div class="panel-body">
<a class="pull-right" href="#" ng-click="toggleDetails(collapsed)">{{hypshowhide}}</a>
<div>
<!--ng-hide="dethide">-->
{{bkdet.name}}
</div>
<!--<details collapsed="no"></details>-->
<details></details>
</div>
</div>
</div>
</script>
<script type="text/ng-template" id="details.html">
<div class="container" ng-hide="bkdet.collapsed">
<div class="row">
<ul class="list-group list-unstyled">
<!--<li>
<h1>Author:</h1>
</li>
<li>
<ul>-->
<li>
<strong>Author</strong>
{{bkdet.author.name}}
</li>
<li>
<strong>Age</strong>
{{bkdet.author.age}}
</li>
<li>
<strong>Country</strong>
{{bkdet.author.country}}
</li>
<li>
<div ng-if="bkdet.list.length == 0">
<p>No books here!</p>
</div>
<div ng-repeat="c in bkdet.list">
<p>
{{c.name}}
<button class="btn btn-danger" ng-click="removeItem($index)">X</button>
</p>
</div>
</li>
<!--</ul>
</li>-->
</ul>
</div>
</div>
</script>
</div>

AngularJS: I clearly do not understand the use of ng-init

I have an extremely hierarchical JSON structure as a scope variable in my AngularJS controller. I want to loop around different sections of that variable. I thought about using ng-init to specify where in the structure I am. Here is some code:
my_app.js:
(function() {
var app = angular.module("my_app");
app.controller("MyController", [ "$scope", function($scope) {
$scope.things = {
name: "a",
children: [
{
name: "a.a",
children: [
{ name: "a.a.a" },
{ name: "a.a.b" }
]
},
{
name: "a.b",
children: [
{ name: "a.b.a" },
{ name: "a.b.b" }
]
}
]
}
}]);
});
my_template.html:
<div ng-app="my_app" ng-controller="MyController">
<ul>
<li ng-init="current_thing=things.children[0]" ng-repeat="thing in current_thing.children>
{{ thing.name }}
</li>
</ul>
</div>
I would expect this to display a list:
a.a.a
a.a.b
But it displays nothing.
Of course, if I specify the loop explicitly (ng-repeat="thing in things.children[0].children") it works just fine. But that little snippet of template code will have to be run at various points in my application at various levels of "things."
(Just to make life complicated, I can get the current thing level using standard JavaScript or else via Django cleverness.)
Any ideas?
ng-init runs at a lower priority (450) than ng-repeat (1000). As a result, when placed on the same element, ng-repeat is compiled first meaning that the scope property created by ng-init won't be defined until after ng-repeat is executed.
As a result, if you want to use it in this manner, you'd need to place it on the parent element instead.
<div ng-app="my_app" ng-controller="MyController">
<ul ng-init="current_thing=things.children[0]">
<li ng-repeat="thing in current_thing.children>
{{ thing.name }}
</li>
</ul>
</div>

Mixitup Angular.js directive (Angular.js watch doesn't work)

I need to integrate Angular.js with Mixitup, so I created directive like that
this is JSFiddle to my code: http://jsfiddle.net/zn7t9p6L/19/
var app = angular.module('app', []);
app.directive('mixitup',function(){
var linker = function(scope,element,attrs) {
scope.$watch('entities', function(){
console.log('reload');
element.mixItUp();
// how to tell mixitup to reload the data
});
console.log('starting')
};
return {
restrict:'A',
link: linker,
scope:{entities:'='}
}
})
app.controller('DrawingsController',
function DrawingsController($scope, $timeout) {
$scope.categories = ['Soft', 'Elements'];
$scope.drawings = [{
name: 'Water',
category: 'Elements',
value: '2'
}, {
name: 'Fire',
category: 'Elements',
value: '1'
}, {
name: 'Air',
category: 'Elements',
value: '4'
}, {
name: 'Coton',
category: 'Soft',
value: '3'
}, {
name: 'Whool',
category: 'Soft',
value: '5'
}];
$scope.add = function(){
$scope.drawings.push({name:'new soft',value:$scope.drawings.length,category:'Soft'})
console.dir($scope.drawings);
};
});
<script src="http://cdn.jsdelivr.net/jquery.mixitup/2.0.4/jquery.mixitup.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<div ng-controller="DrawingsController">
<div class="controls">
<label>Filter:</label>
<button class="filter" data-filter="all">All</button>
<button class="filter"
data-filter=".category-{{category}}"
ng-repeat="category in categories">{{category}}</button>
<label>Sort:</label>
<button class="sort" data-sort="myorder:asc">Asc</button>
<button class="sort" data-sort="myorder:desc">Desc</button>
<label>Add:</label>
<button data-ng-click="add()">Add</button>
</div>
<div mixitup='mixitup' class="container" entities='drawings'>
<div class="mix category-{{drawing.category}}"
data-myorder="{{drawing.value}}"
ng-repeat="drawing in drawings">Value : {{drawing.name}}</div>
</div>
</div>
My problem is when I try to add new element to the drawings array or even change the array, it doesn't reflect the changes immediately, you need to make some filters like sorting to reflect changes.
Also the watcher to "entities" work once at the beginning and doesn't work anymore when any changes happen later to the drawings array (it will print reload one time and will not print it anymore)
you can try it in jsfiddle
You can try to pass a 3rd argument to .$watch() as true.
http://docs.angularjs.org/api/ng.$rootScope.Scope
$watch(watchExpression, listener, objectEquality)
objectEquality(optional) – {boolean=} – Comparing the object for equality rather than for reference.
I found the answer after some digging
As #gayu said , the first step is to set the 3rd argument to be true this will fix the second problem of the watcher
To fix the first problem which is updating mixitup immediately , you will need to add this script to the watcher callback
element.mixItUp();
if(element.mixItUp('isLoaded')){
element.mixItUp('destroy', true);
element.mixItUp();
}
this the new JSfiddle : http://jsfiddle.net/zn7t9p6L/20/

Categories