Angular js : call the parent id, if parent has no children - angularjs

My problem is that I have parents item that do not have children, they are called with their Id, the remaining called with her children-id
controller:
var listContent = angular.module('app', []);
listContent.controller('Cnt', function($scope) {
$scope.products = [{
"id": 10,
"name": "Samsung",
"children": [{
"id": 1122,
"name": "Galaxy S5"
}, {
"id": 1123,
"name": "Galaxy Note 4"
}, {
"id": 1124,
"name": "Galaxy S5 Mini"
}]
}, {
"id": 11,
"name": "LG",
"children": [{
"id": 25,
"name": "L70"
}, {
"id": 23,
"name": "G2"
}, {
"id": 24,
"name": "G3"
}]
}, {
"id": 12,
"name": "own",
"children": []
}];
});
**html code:**
<nav>
<div data-ng-class="procedures" data-ng-controller="Cnt">
<ul data-ng-repeat="parent in products">
<li>
<h4 data-ng-click="showDetails = ! showDetails">
<a>{{parent.name}}</a>
</h4>
** bei product "own", should call the parent-id , it should look like
<h4>
<a data-ng-href="http://....{{parent.id}}">{{parent.name}}</a>
</h4>
**
<ul class="procedure-details" data-ng-class="{ 'hidden': ! showDetails }">
<li data-ng-repeat="child in parent.children">
<a data-ng-href="http://....{{child.id}}">{{child.name}}</a>
</li>
</ul>
</li>
</ul>
</div>
</nav>
CSS
<style type="text/css">
li {
list-style: none;
padding: 0px;
border-bottom: 1px solid #eee;
}
.procedure-details {
max-height: 100px;
transition: .5s;
overflow: hidden;
background: #fff;
font-size: 13px;
}
.procedure-details.hidden {
max-height: 0;
}
ul {
margin: 0;
padding: 0;
}
nav {
font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
line-height: 2;
width: 100%;
}
</style>

If I understand correctly, you want to have some html when a manufacturer has child products which shows links to all of those products. If a manufacturer does not have any products then you want to show a link to the manufacturer instead.
One way of doing this is using the ng-if directive to switch between different html.
<h4 ng-if="!parent.children.length">
<a data-ng-href="http://....{{parent.id}}">{{parent.name}}</a>
</h4>
<ul ng-if="parent.children.length" class="procedure-details" data-ng-class="{ 'hidden': ! showDetails }">
<li data-ng-repeat="child in parent.children">
<a data-ng-href="http://....{{child.id}}">{{child.name}}</a>
</li>
</ul>
This works because the length will be 0 if the array of children is empty, which is a falsey value.
Also consider using the ng-switch directive to better document the fact that these two sections of html are mutually exclusive.

Problem solved as follows :
<li data-ng-click="showDetails = ! showDetails">
<h4 data-ng-if="!parent.children.length">
{{parent.name}}
</h4>
<h4 data-ng-if="parent.children.length">
<a>{{parent.name}}</a>
</h4>
<ul class="procedure-details"
data-ng-class="{ 'hidden': ! showDetails }">
<li data-ng-click="showDetails = showDetails"
data-ng-repeat="child in parent.children"><a
data-ng-href="http://">{{child.name}}</a></li>
</ul>
</li>

Related

VueJS v-for: remove duplicates

Is there a simple solution I can use to remove the duplicates from my v-for loop which is looping through the JSON data.
I'm using this to populate a Select option and would rather not import https://lodash.com/docs#uniq
Codepen with issue: https://codepen.io/anon/pen/JaZJmP?editors=1010
Thanks
Create a computed property that returns only those items from your array which you want/need. To remove duplicates from info, you can do new Set(this.info.map(i=>i.title.rendered) and destructure that back into an array using [...new Set(this.map(i=>i.title.rendered))]:
var vm = new Vue({
el: "#wp-vue-app",
data() {
return {
info: [{
id: 1,
status: "publish",
link: "",
title: {
rendered: "Test Name One"
},
acf: {
employee_details: {
employee_name: "Test Name",
employee_email: "Test-Email#email.co.uk",
employee_number: "123",
cost_centre_manager: "Manager Name",
manager_email: "Manager-Email#email.co.uk"
}
}
},
{
id: 2,
status: "publish",
link: "",
title: {
rendered: "Test Name"
},
acf: {
employee_details: {
employee_name: "Test Two Name",
employee_email: "Test-Two-Email#email.co.uk",
employee_number: "1234",
cost_centre_manager: "Manager Two Name",
manager_email: "Manager-Two-Email#email.co.uk"
}
}
},
{
id: 3,
status: "publish",
link: "",
title: {
rendered: "Test Name"
},
acf: {
employee_details: {
employee_name: "Test Three Name",
employee_email: "Test-Three-Email#email.co.uk",
employee_number: "12345",
cost_centre_manager: "Manager Three Name",
manager_email: "Manager-Three-Email#email.co.uk"
}
}
}
],
loading: true,
errored: false,
emp_manager: "All",
emp_cost_centre: "All"
};
},
computed: {
info_title: function() {
return [...new Set(this.info.map(i => i.title.rendered))]
},
info_employee_name: function() {
return [...new Set(this.info.map(i => i.acf.employee_details.employee_name))]
},
},
});
.container {
padding: 20px;
width: 90%;
max-width: 400px;
margin: 0 auto;
}
label {
display: block;
line-height: 1.5em;
}
ul {
margin-left: 0;
padding-left: 0;
list-style: none;
}
li {
padding: 8px 16px;
border-bottom: 1px solid #eee;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script>
<div id="wp-vue-app">
<section v-if="errored">
<p>We're sorry, we're not able to retrieve this information at the moment, please try back later</p>
</section>
<section v-else>
-
<div class="row">
<div class="col">
<select class="form-control" v-model="emp_manager">
<option>All</option>
<option v-for="item in info_title" :value="item">{{ item }}</option>
</select>
<span>Selected: {{ emp_manager }}</span>
</div>
<div class="col">
<select class="form-control" v-model="emp_cost_centre">
<option>All</option>
<option v-for="item in info_employee_name" :value="item">{{ item }}</option>
</select>
<span>Selected: {{ emp_cost_centre }}</span>
</div>
</div>
<br />
</section>
</div>
https://codepen.io/anon/pen/bxjpKG
You can use a computed property to filter your info (let's say filteredInfo). Then use v-for on the filteredInfo property.

Angular + jquery ui sortable

Look in this fiddle https://jsfiddle.net/Lj0swckj/3/
I have created directive for sortable
For parent divs sortable working fine
I want same thing for childs also with containment as its parent
In the given example child1, child2, child3 can swap positions and containment will be parent1.
I tried a lot but can't find anything
Note: There can also children for a child1, child2...
(Here In this example i have added data for two levels but it can be upto four levels)
So I want a solution where sortable can work for such kind of recursive templates.
Any Help would be appreciated.
angular.module("myApp", []).
controller("myController", ['$scope', function($scope) {
$scope.fields = [{
"name": "parent1",
"level": 1,
"children": [{
"name": "child1",
"level": 2
}, {
"name": "child2",
"level": 2
}, {
"name": "child3",
"level": 2
}]
}, {
"name": "parent2",
"level": 1
}, {
"name": "parent3",
"level": 1
}];
$scope.draggableItemsOption = {
"moverElement": ".moverBtn",
"containment": ".draggable-field"
}
}]).directive("myDragDrop", ['$timeout', function ($timeout) {
return {
restrict:'A',
scope: {
myDragDrop:"="
},
link: function ($scope, element, attrs) {
var options = $scope.myDragDrop;
var $container = element;
var sortableOptions = {
/* handle: options.moverElement, */
containment: options.containment,
delay: 0
};
if($container.sortable){
$container.sortable(sortableOptions);
}
}
}
}]);
.element {
border: 1px solid #333;
padding: 10px 10px;
position: relative;
}
.element-class {
margin-left: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<div class="draggable-field" my-drag-drop="draggableItemsOption">
<div ng-repeat="data in fields">
<div class="element" ng-class="{'element-class': data.level > 1}">
{{data.name}}
<div ng-repeat="childData in data.children">
<div class="element" ng-class="{'element-class': data.level > 1}">
{{childData.name}}
</div>
</div>
</div>
</div>
</div>
</div>
Huh ! Finally Got a solution.
Actually it is pretty simple
Here look at this fiddle https://jsfiddle.net/Lj0swckj/6/
What I did is created child elems
angular.module("myApp", []).
controller("myController", ['$scope', function($scope) {
$scope.fields = [{
"name": "parent1",
"level": 1,
"children": [{
"name": "child1",
"level": 2
}, {
"name": "child2",
"level": 2
}, {
"name": "child3",
"level": 2,
"children": [{
"name": "grandChild1",
"level": 3
}, {
"name": "grandChild2",
"level": 3
}]
}]
}, {
"name": "parent2",
"level": 1,
"children": [{
"name": "child4",
"level":2
}]
}, {
"name": "parent3",
"level": 1
}];
$scope.draggableItemsOption = {
"moverElement": ".moverBtn",
"containment": ".draggable-field"
}
$scope.childDraggableItemsOption = {
"containment": "parent"
}
}]).directive("myDragDrop", ['$timeout', function ($timeout) {
return {
restrict:'A',
scope: {
myDragDrop:"="
},
link: function ($scope, element, attrs) {
var options = $scope.myDragDrop;
var $container = element;
var sortableOptions = {
/* handle: options.moverElement, */
containment: options.containment,
delay: 0
};
if($container.sortable){
$container.sortable(sortableOptions);
}
}
}
}]);
.element {
border: 1px solid #333;
padding: 10px 10px;
position: relative;
}
.element-class {
margin-left: 20px;
}
.moverBtn {
position: absolute;
top: 2px;
right: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-autocomplete/1.0.7/jquery.auto-complete.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<script type="text/ng-template" id="tree_item_renderer.html">
<div class="child-draggable-field" my-drag-drop="childDraggableItemsOption">
<div ng-repeat="data in data.children" ng-class="{'element-class': data.level > 1}">
<div class="element"> {{data.name}} ------ {{$parent.$parent.data.children.length}}</div>
<div ng-include="'tree_item_renderer.html'">
</div>
</div>
</div>
</script>
<div class="draggable-field" my-drag-drop="draggableItemsOption">
<div ng-repeat="data in fields">
<div class="element" ng-class="{'element-class': data.level > 1}">
{{data.name}}
<div ng-include="'tree_item_renderer.html'">
</div>
</div>
</div>
</div>
</div>

Angularjs Nested Md-Virtual repeat

I have the following JSON object:
[
{
"districtId": 1,
"districtAddress": "108 N MAIN ST",
"offices": [
{
"Id": 11,
"name": "test",
"City": "ATMORE"
},
{
"Id": 22,
"name": "test",
"City": "ATMORE"
}
]
},
{
"districtId": 2,
"districtAddress": "108 N MAIN ST",
"offices": [
{
"Id": 33,
"name": "test",
"City": "ATMORE"
},
{
"Id": 44,
"name": "test",
"City": "ATMORE"
}
]
},
{
"districtId": 3,
"districtAddress": "108 N MAIN ST",
"offices": [
{
"Id": 55,
"name": "test",
"City": "ATMORE"
}
]
}
]
I want to show this data using md-virtual-repeat directive. First level repeater works when I use this directive.
But when I try to render the inner data using the same directive - it doesn't work as expected. How can use md-virtual-repeat for the nested repeater (I want to get rid of ng-repeat on md-list-item element)?
Here is my code:
angular
.module('MyApp',['ngMaterial'])
.controller('AppCtrl', function($scope) {
var self = this;
self.items = [];
for (var i = 0; i < 1000; i++) {
var item = {
nbr: i,
items: []
};
for(var m = 0; m < 10; m++) {
item.items.push({
nbr: m,
checked: true
});
}
self.items.push(item);
}
});
.virtualRepeatStoreList .vertical-container {
height: 500px;
width: 100%;
}
.virtualRepeatStoreList .repeated-item {
border-bottom: 1px solid #ddd;
box-sizing: border-box;;
height: 40px;
padding-top: 10px;
}
.virtualRepeatStoreList md-content {
margin: 16px;
}
.virtualRepeatStoreList .md-virtual-repeat-container .md-virtual-repeat-offsetter div {
padding-left: 5px;
}
<link rel="stylesheet prefetch" href="https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.0/angular-material.css">
<link rel="stylesheet prefetch" href="https://material.angularjs.org/1.1.0/docs.css">
<div ng-controller="AppCtrl as ctrl" class="content virtualRepeatStoreList" ng-app="MyApp">
<md-virtual-repeat-container class="vertical-container" style="height:550px">
<div md-virtual-repeat="item in ctrl.items">
<md-card flex="">
<md-card-title>
<md-card-title-text>
<span class="md-display-2">{{ item.nbr }}</span>
</md-card-title-text>
</md-card-title>
<md-list style="overflow:auto;height:auto;" flex ng-cloak layout="column">
<md-divider></md-divider>
<md-list-item layout="row" class="noright">
<md-subheader flex>Item</md-subheader>
</md-list-item>
<md-list-item ng-repeat="it in item.items" style="max-height:40px;overflow:hidden;" class="noright">
<p>{{ it.nbr }}</p>
<md-checkbox class="md-secondary" ng-model="it.checked"></md-checkbox>
</md-list-item>
</md-list>
</md-card>
</div>
</md-virtual-repeat-container>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-aria.min.js"></script>
<script src="https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.0/angular-material.js"></script>
You need to wrap each nested md-virtual-repeat with md-virtual-repeat-container like:
angular
.module('MyApp',['ngMaterial'])
.controller('AppCtrl', function($scope) {
var self = this;
self.items = [];
for (var i = 0; i < 1000; i++) {
var item = {
nbr: i,
items: []
};
for(var m = 0; m < 10; m++) {
item.items.push({
nbr: m,
checked: true
});
}
self.items.push(item);
}
});
.virtualRepeatStoreList .vertical-container {
height: 500px;
width: 100%;
}
.virtualRepeatStoreList .repeated-item {
border-bottom: 1px solid #ddd;
box-sizing: border-box;;
height: 40px;
padding-top: 10px;
}
.virtualRepeatStoreList md-content {
margin: 16px;
}
.virtualRepeatStoreList .md-virtual-repeat-container .md-virtual-repeat-offsetter div {
padding-left: 5px;
}
md-list-item.md-no-proxy.md-no-padding {
padding: 0;
}
<link rel="stylesheet prefetch" href="https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.0/angular-material.css">
<link rel="stylesheet prefetch" href="https://material.angularjs.org/1.1.0/docs.css">
<div ng-controller="AppCtrl as ctrl" class="content virtualRepeatStoreList" ng-app="MyApp">
<md-virtual-repeat-container class="vertical-container" style="height:550px">
<div md-virtual-repeat="item in ctrl.items">
<md-card flex="">
<md-card-title>
<md-card-title-text>
<span class="md-display-2">{{ item.nbr }}</span>
</md-card-title-text>
</md-card-title>
<md-list style="overflow:auto;height:auto;" flex ng-cloak layout="column">
<md-divider></md-divider>
<md-list-item layout="row" class="noright md-no-padding">
<md-subheader flex>Item</md-subheader>
</md-list-item>
<md-virtual-repeat-container class="vertical-container" style="height:125px">
<md-list-item md-virtual-repeat="it in item.items" style="max-height:40px;overflow:hidden;" class="noright">
<p>{{ it.nbr }}</p>
<md-checkbox class="md-secondary" ng-model="it.checked"></md-checkbox>
</md-list-item>
</md-virtual-repeat-container>
</md-list>
</md-card>
</div>
</md-virtual-repeat-container>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.2/angular-aria.min.js"></script>
<script src="https://cdn.gitcdn.link/cdn/angular/bower-material/v1.1.0/angular-material.js"></script>

angular-drag-and-drop-lists simple demo doesn't work

I was having a problem getting the simple demo to work found here.
I'm getting the two lists to show up, however I am unable to drag and drop items. The demo is very simple, just an html file, javascript file and css file.
Here's my index.html file:
<!DOCTYPE html>
<html ng-app="demo">
<head lang="en">
<meta charset="utf-8">
<title>Drag & Drop Demo</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="bower_components/angular-drag-and-drop-lists/angular-drag-and-drop-lists.min.js"></script>
<script src="Scripts/my-app.js"></script>
<link href="Content/my-styling.css" rel="stylesheet" />
</head>
<body class="simpleDemo" ng-controller="SimpleDemoController">
<ul dnd-list="list">
<li ng-repeat="item in models.lists.A"
dnd-draggable="item"
dnd-moved="models.lists.A.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}">
{{item.label}}
</li>
</ul>
<ul dnd-list="list">
<li ng-repeat="item in models.lists.B"
dnd-draggable="item"
dnd-moved="models.lists.B.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}">
{{item.label}}
</li>
</ul>
</body>
</html>
Here's my js file:
angular.module("demo", []).controller("SimpleDemoController", function ($scope) {
$scope.models = {
selected: null,
lists: { "A": [], "B": [] }
};
// Generate initial model
for (var i = 1; i <= 3; ++i) {
$scope.models.lists.A.push({ label: "Item A" + i });
$scope.models.lists.B.push({ label: "Item B" + i });
}
// Model to JSON for demo purpose
$scope.$watch('models', function (model) {
$scope.modelAsJson = angular.toJson(model, true);
}, true);
});
And here's my css file:
.simpleDemo ul[dnd-list],
.simpleDemo ul[dnd-list] > li {
position: relative;
}
.simpleDemo ul[dnd-list] {
min-height: 42px;
padding-left: 0px;
}
.simpleDemo ul[dnd-list] .dndDraggingSource {
display: none;
}
.simpleDemo ul[dnd-list] .dndPlaceholder {
display: block;
background-color: #ddd;
min-height: 42px;
}
.simpleDemo ul[dnd-list] li {
background-color: #fff;
border: 1px solid #ddd;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
}
.simpleDemo ul[dnd-list] li.selected {
background-color: #dff0d8;
color: #3c763d;
}
This code is simply copied and pasted from the simple demo, just slightly modified to show lists A and B. Does anyone know what's wrong?
You're forgetting Dependency Injection just replace
angular.module("demo", [])
with
angular.module("demo", ['dndLists'])
and it should work..
plunk
--Update--
I found some problem with your Markup as well you are referencing list in <ul dnd-list="list>" this will not work as you're referencing an undefined variable, you should be referencing the list you are using in the drag-able. for example for the first list you can change.
<ul dnd-list="list">
to
<ul dnd-list="models.lists.A">
and that should work properly now..
P.S I've updated the plunk
you need the next: (that is the dependency injection)
app.requires.push('dndLists');
you are missing the ng-repeat in your angular it should look like this: (ng-repeat="(listName, list) in models.lists")
<div ng-repeat="(listName, list) in models.lists" class="col-md-6 ng-scope">
<div class="panel panel-info">
<div class="panel-heading">
<h3 class="panel-title ng-binding">List A</h3>
</div>
<div class="panel-body ng-scope">
<ul dnd-list="list" class="ng-scope">
<li ng-repeat="item in list"
dnd-draggable="item"
dnd-moved="list.splice($index, 1)"
dnd-effect-allowed="move"
dnd-selected="models.selected = item"
ng-class="{'selected': models.selected === item}"
dnd-disable-if="list.length < 2"
class="ng-binding ng-scope"
draggable="true">
{{item.label}}
</li>
</ul>
</div>
</div>
</div>

backbone : Collection and View rendering

I am really confused on this one and need help. (unrelated : "up for about 36 hours now to finish somthing and this last part is just making me go crazy")
My Code
<body>
<div id="mycontainer" style="margin: 20px; ">
</div>
<script type="text/template" id="Myelement_template">
<% _.each( results, function( item, i ){ %>
<div id="Myelement" style="width: 200px; height:325px; padding: 10px; background-color: #2980b9;">
<div id="image" style="width: 190px; height: 200px; margin: auto; background-color: #f1c40f;">
<img src="<%= item.get('category').url %>" style="max-width: 90%;margin-top: 10px;">
</div>
<div id="type" style="float:left;width: 90px; height: 25px; margin-left: 5px;margin-top: 5px;background-color: #f1c40f;">
<%= item.get("category").type %>
</div>
<div id="name" style="float:left;width: 90px; height: 25px; margin-left: 10px; margin-top: 5px;background-color: #f1c40f;">
<%= item.get("category").name %>
</div>
</div>
<% }); %>
</script>
<script type="text/javascript">
$(document).ready(function() {
CategoryModel = Backbone.Model.extend({
defaults: {
url: '',
type: '',
name: ''
}
});
MyListModal = Backbone.Model.extend({
url: 'myrestapi',
defaults: {
category: CategoryModel
}
});
MyElementView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render'); // bind 'this' in 'render'
this.model = new MyListModal();
this.model.bind('change', this.render);
this.model.fetch(this.render);
},
el: $("#mycontainer"),
render: function(){
console.log(this.model.get("category"));
}
});
var myModelView = new MyElementView();
});
</script>
Question
My rest api will return many BaseModel objects. All of them need to be rendered. How do I do that?
console.log(this.model.get("category")); - code reaches here. not printing. debugging shows that rest api call was made and cata has been returned
How do I render all returned elements?
Sample Data returned by rest API
[
{
"category": {
"id": 1,
"name": "name1",
"type": "mytype1",
"url": "myurl1"
},
"user": {
"id": 153
},
"status": 1
},
{
"category": {
"id": 1,
"name": "name2",
"type": "type2",
"url": "url2"
},
"user": {
"id": 153
},
"status": 1
},
]

Resources