Angular + jquery ui sortable - angularjs

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>

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.

How can I apply ng-style dynamically if ng-class is true?

.test{color:red;background:blue;}
.test.selected {
position:relative; left: 100px; padding:10px; background:green;
}
<div ng-style="myStyle" ng-class="{select: x.selected}" ng-click="select(x)" ng-repeat="x in myData" class="test"></div>
$scope.select = function (text) {
text.selected = true;
};
$scope.myStyle = {
'color':'white',
'font-weight':'bold'
}
When the div element has className "selected" by using condition true, how can I add 'myStyle' in ng-style as well. How to apply inline ng-style dynamically if ng-class condition is true? Here below I am able to see in debugger in inline with classNames added. Now I have the condition true and I can see the classname "selected" to it(class="test ng-scope selected"), All I want is an inline ng-style="myStyle" to be added when its true.
<div ng-class="{select: x.selected}" ng-click="select(x)" class="test ng-scope selected" ng-repeat="x in myData">
Try like to this.
<div ng-style="x.selected && {'color':'white','font-weight':'bold'}"
ng-click="select(x)" ng-repeat="x in myData" ></div>
Demo
var app = angular.module('anApp', ['angular.filter']);
app.controller('aCtrl', function($scope) {
$scope.data = [
{
"id": 100,
"value": "2452"
},
{
"id": 100,
"value": "2458"
},
{
"id": 1,
"value": "2457"
},
{
"id": 1,
"value": "2459"
},
{
"id": 4,
"value": "2460"
},
{
"id": 5,
"value": "3458"
}
];
$scope.select = function(x){
x.selected = !x.selected;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<div ng-app="anApp" ng-controller="aCtrl">
<div ng-style="x.selected && {'color':'red','font-weight':'bold'}"
ng-click="select(x)" ng-repeat="x in data" >
{{x.value}}
</div>
</div>
Dont use ng-style for selected item, you can do this with ng-class(Recommended)
Style
.selected {
'color':'white',
'font-weight':'bold'
}
HTML
<div ng-class="{'selected': x.selected}" ng-click="select(x)" ng-repeat="x in myData" ></div>
Controller
$scope.select = function(x){
x.selected = !x.selected;
}

How to find minimum value in ng-repeat?

Hi i'm trying to get the minimum price in my repeater. I'll add a green sign near to this list item. (as you see in code, "span class min-value")
How can I get this minimum value and use my span as "ng-show" in my html?
Thank you.
var app = angular.module("App", []);
app.controller("Controller", function($scope) {
$scope.priceList = [{
"name": "Product 1",
"price": "100"
}, {
"name": "Product 2",
"price": "200"
}, {
"name": "Product 3",
"price": "300"
}, {
"name": "Product 4",
"price": "400"
}, {
"name": "Product 5",
"price": "500"
}];
});
li {
padding: 10px;
}
.min-price {
width: 10px;
height: 10px;
background: green;
display: inline-block;
border-radius: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<html lang="en" ng-app="App">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body ng-controller="Controller">
<ul>
<li ng-repeat="item in priceList">
{{item.name}} - {{item.price}}$
<span class="min-price" ng-show="true"></span>
</li>
</ul>
</body>
</html>
Here is simple logic for you:-
<span class="min-price" ng-show="isMin(item.price)"></span>
$scope.isMin=function(price){
var min=$scope.priceList[0].price;
for(var i=0;i<= $scope.priceList.length-1;i++){
if(Number($scope.priceList[i].price) < min){
min=$scope.priceList[i].price;
console.log("Min"+min);
}
}
console.log("min:"+min+ " price:"+price);
if(min===price){
return true;
}else{
return false;
}
}
Plunker
Compute the minimum price in the controller, using JavaScript code, and store the result in a scope variable (minimumPrice for example).
Then use
ng-show="item.price == minimumPrice"
Hint: don't use strings to represent numbers. Use numbers.

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

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>

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