Usng Sidr to create multiple level navigation - responsive-design

I'm using Sidr to create a multilevel (nested) menu. I'm aiming to achieve a responsive menu like: http://www.currys.co.uk
I've got the 2nd level navigation working well, but haven't been able to get any further levels working.
HTML:
<nav class="nav">
<ul class="menu">
<li class="left-menu">Level 1 Example
<ul class="subnav-l2">
<li class="close">Close Menu</li>
<li>Level 2 Example</li>
<li>Level 2 Example</li>
<li>Level 2 Example</li>
<li class="left-menu-l3">Level 3 Example
<ul class="subnav-l3">
<li>Link Example</li>
<li>Link Example 2</li>
<li>Link Example 3</li>
<li>Link Example 4</li>
</ul>
</li>
<li>Official Report</li>
</ul>
</li>
<li>Level 1 Example
</ul>
</nav>
JS:
$('.left-menu').sidr({
name: 'sidr-left',
side: 'left', // By default
source: '.subnav-l2'
});
$('.left-menu-l3').sidr({
name: 'sidr-left2',
side: 'left', // By default
source: '.subnav-l3'
});

This should be in your footer. Hope this helps.
<script src="http://yoursite.domain.../jquery.sidr.min.js"></script>
<script>
jQuery('#responsive-menu-button').sidr({
name: 'sidr-main',
source: '.menu-main-nav-container'
});
jQuery( window ).load(function() {
if(jQuery("#sidr-main").length !== 0) {
jQuery(".sidr-class-sub-menu").hide();
jQuery( "li.sidr-class-menu-item ul.sidr-class-sub-menu" ).each(function() {
jQuery( this ).after("<div class='lnk-plus'>+</div>");
});
jQuery( ".lnk-plus" ).toggle(function() {
var id1= jQuery( this ).parent().attr("id");
jQuery("#" + id1 + " ul.sidr-class-sub-menu").show();
jQuery("#" + id1 + " .sidr-class-menu-item-has-children ul").hide();
jQuery( this ).html("-");
}, function() {
var id1= jQuery( this ).parent().attr("id");
jQuery("#" + id1 + " ul.sidr-class-sub-menu").hide();
jQuery( this ).html("+");
});
}
});
</script>
Please notice where jQuery(".sidr-class-sub-menu").hide(); is situated.
For iPad and iPhone, you have to use a separate snippet which is slightly different, it uses .bind and touchstart event to make it work.
<script>
jQuery(document).ready(function($){
var deviceAgent = navigator.userAgent.toLowerCase();
var agentID = deviceAgent.match(/(ipad|iphone)/);
if (agentID) {
jQuery('#responsive-menu-button').sidr({
name: 'sidr-main',
source: '.menu-main-nav-container'
});
if(jQuery("#sidr-main").length !== 0) {
jQuery(window).bind('touchstart click', function(){
//return false
});
jQuery( ".lnk-plus" ).toggle(function() {
var id1= jQuery( this ).parent().attr("id");
jQuery("#" + id1 + " ul.sidr-class-sub-menu").show("slow");
jQuery("#" + id1 + " .sidr-class-menu-item-has-children ul").hide("slow");
jQuery( this ).html("-");
}, function() {
var id1= jQuery( this ).parent().attr("id");
jQuery("#" + id1 + " ul.sidr-class-sub-menu").hide("slow");
jQuery( this ).html("+");
});
}
}
});
</script>

Related

List folders under clicked folder

I want to ng-repeat only this catalogs of folders, which is clicked.
Here is my HTML :
<li class="left-menu-list-submenu">
<a class="left-menu-link" href="javascript: void(0);" ng-click="getfolders();">
<i class="left-menu-link-icon fa fa-folder"></i>
Catalogs
</a>
<ul class="left-menu-list list-unstyled" style="margin-left:20px;" ng-repeat="fol in folders">
<li>
<a style="cursor:pointer;" ng-click="more_folders();">{{fol}}</a>
<br />
<a style="cursor:default;color:black;" ng-repeat="more in more_folders | filter:fol">
<ul>
<li>{{more}}</li>
</ul>
</a>
</li>
</ul>
</li>
JS:
$scope.getfolders = function(){
$http({
method: 'GET' ,
url: 'link_folders.json',
})
.then(function successCallback(data) {
console.log("folders");
$scope.folders = data.data;
}, function errorCallback(response) {
console.log(response);
console.log('error');
});
};
$scope.getfolders();
$scope.more_folders = function(){
$http({
method: 'GET' ,
url: 'more_folders.json',
})
.then(function successCallback(data) {
console.log("more_folders");
$scope.more_folders = data.data;
}, function errorCallback(response) {
console.log(response);
console.log('error');
});
};
link_folders.json :
[
"/visualizer/360",
"/visualizer/2D"
]
more_folders.json :
[
"/visualizer/360/Eva",
"/visualizer/2D/Ferb",
"/visualizer/360/Andy",
"/visualizer/2D/John"
]
My plunker : https://plnkr.co/edit/N18FNNRgd1YuYKTKlc3H?p=preview
I want to list more_folders under the clicked folder, not under every folders
Thanks for answers in advance!
To make a toggle type folder structure, You need to maintain a selected folder somewhere in your controller. So you know which folder is clicked and if clicked again, then you can toggle it.
Here is how you can do it.
var miAp = angular.module('miAp', []);
miAp.controller('miControlador', function($scope, $http) {
var vm = this;
$scope.getfolders = function() {
$scope.folders = [
"/visualizer/360",
"/visualizer/2D"
];
};
$scope.getfolders();
$scope.more_folders = function() {
$scope.more_folders = [
"/visualizer/360/Eva",
"/visualizer/2D/Ferb",
"/visualizer/360/Andy",
"/visualizer/2D/John"
];
};
$scope.more_folders();
$scope.selectedFol = null;
$scope.toggle = (fol) => {
if ($scope.selectedFol === fol) {
$scope.selectedFol = null;
} else {
$scope.selectedFol = fol;
}
};
});
<html>
<head>
<meta charset="utf-8">
<title>Cookies</title>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script src="cookies.js"></script>
</head>
<body ng-app="miAp">
<div class="container" ng-controller="miControlador">
<li class="left-menu-list-submenu">
<a class="left-menu-link" href="javascript: void(0);" ng-click="getfolders();">
<i class="left-menu-link-icon fa fa-folder"></i> Catalogs
</a>
<ul class="left-menu-list list-unstyled" style="margin-left:20px;" ng-repeat="fol in folders">
<li>
<a style="cursor:pointer;" ng-click="toggle(fol);">{{fol}}</a>
<br />
<div id="childFolders" ng-show="selectedFol === fol">
<a style="cursor:default;color:black;" ng-repeat="more in more_folders | filter:fol">
<ul>
<li>{{more}}</li>
</ul>
</a>
</div>
</li>
</ul>
</li>
</div>
</body>
</html>
PS: If you want to toggle Root Folder as well, then you can maintain another variable in the same way for root.

Angular JS - Nested JSON Driving a Two Level Navigation - How to Alter scope from directive?

I'm new to Angular but enjoying getting to know it! I'm having no problem populating data but I'm stuck on this navigational problem.
I have a sidebar divided into two navigation s. Both are reading from nested JSON of 'areas' and 'reports'. The idea is that the currently selected/clicked item in the left hand list will populate the elements in the right hand list, according to its children in the JSON.
I've got the initial population working fine. It reads the 'areas' and assigns the active area, which displays the reports. I then have a directive which applies css classes on the click event, but how can I get it to also alter the active area?
I'm currently doing scope.activeArea = scope.areas[1];, but this does not work. The index is just there for development; that will be replaced by the index of the clicked element.
My HTML:
<div id="reports-subnav" ng-controller="reportAreasController">
<ul class="subnav-areas" >
<li ng-repeat="x in areas">
<a class="subnav-area-button" href="#" my-cool-directive>
<i class="{{ x.iconClass }}"></i>
</a>
</li>
</ul>
<ul id="nav-subsection" class="subnav-reports">
<li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><span class="{{ r.iconClass }}"></span> {{ r.name }}</li>
</ul>
</div>
And Javascript:
var app = angular.module("focalWeb", []);
app.controller("reportAreasController", ['$scope','$http', function($scope, $http) {
$http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){
$scope.areas = data.areas;
$scope.activeArea = $scope.areas[0];
});
}] );
app.directive("myCoolDirective", function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
$(elem).click(function() {
//var target = $(elem).next(".panel-collapse");
//target.hasClass("collapse") ? target.collapse("show") : target.collapse("hide");
$('.subnav-areas li').removeClass('active');
$(this).parent().addClass('active');
scope.activeArea = scope.areas[1];
});
}
}
});
Thanks!
Edit
Thanks to charlietfl's guidance my code now looks like this:
HTML
<div id="reports-subnav" ng-controller="reportAreasController">
<ul class="subnav-areas" >
<li class="subnav-area" ng-repeat="x in areas">
<a class="subnav-area-button" href="#" ng-click="showReports($event, x.id)">
<i class="{{ x.iconClass }}"></i>
</a>
</li>
</ul>
<ul id="nav-subsection" class="subnav-reports">
<li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><span class="{{ r.iconClass }}"></span> {{ r.name }}</li>
</ul>
</div>
JS
var app = angular.module("focalWeb", []);
app.controller("reportAreasController", ['$scope','$http', function($scope, $http) {
$http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){
$scope.areas = data.areas;
$scope.activeArea = $scope.areas[0];
$scope.showReports = function($event, index) {
$scope.activeArea = $scope.areas[index -1];
var theLi = angular.element($event.currentTarget).parent();
theLi.parent().find('li').removeClass('active');
theLi.addClass('active');
}
});
}] );
Edit 2
HTML
<div id="reports-subnav" ng-controller="reportAreasController">
<ul class="subnav-areas" >
<li class="subnav-area" ng-repeat="x in areas" ng-class="{active: x==activeArea}">
<a class="subnav-area-button" href="#" ng-click="showReports($event, x)">
<i class="{{ x.iconClass }}"></i>
</a>
</li>
</ul>
<ul id="nav-subsection" class="subnav-reports">
<li ng-repeat="r in activeArea.reports" id="{{ r.action }}" role="presentation"><span class="{{ r.iconClass }}"></span> {{ r.name }}</li>
</ul>
</div>
JS
var app = angular.module("focalWeb", []);
app.controller("reportAreasController", ['$scope','$http', function($scope, $http) {
$http.get('<?php echo SITE_ADDR; ?>/data/reportAreas.json').success (function(data){
$scope.areas = data.areas;
$scope.activeArea = $scope.areas[0];
$scope.showReports = function($event, item) {
$scope.activeArea = item;
}
});
}] );
Thanks again charlietfl!

$scope data is not updating in view for the first time

controller.js
$scope.getElectInfo=function(){
var selectedVal = $("#countriesList option:selected").val();
if (selectedVal != 0) {
$.get(APP_URL+ "/political/ElectionType/GetElectionTypesByCountry?countryId="
+ selectedVal,
function(data, status) {
$scope.data1=data;
console.log($scope.data1);
});
$scope.Structure = true;
}else
{
$scope.Structure = false;
}
}
html
<select id="countriesList" ng-change="getElectInfo()" ng-model="getElectionInfo">
</select>
<div ng-show="Structure" class="content">
<figure class="org-chart cf">
<ul class="administration">
<li>
<ul class="director">
<li>
<ul class="subdirector">
</ul>
<ul class="departments cf">
<li><a ><span ng-repeat="cname in country">{{cname.countryName}}</span></a></li>
<li class="department dep-b" ng-repeat="types in data1">
<a ><span>{{types.name}}</span></a>
</li>
In the above controller.js i am getting the country wise election types data,in the html page when i select the country for the first time $scope.data1 is not updating in view,select second time its updating can any one help me what is the problem!
finally i got it,
need to place $scope.$apply(); in function(data, status) { }

How to make dynamically Tree View with input in AngularJS?

I'm looking to add contents like division, input text, button... in a tree structure in a web app. I was hoping to use Angular for this task.
HTML:
<script type="text/ng-template" id="tree_item_renderer.html">
{{data.name}}
<button ng-click="add(data)">Add node</button>
<button ng-click="delete(data)" ng-show="data.nodes.length > 0">Delete nodes</button>
<ul>
<li ng-repeat="data in data.nodes" ng-include="'tree_item_renderer.html'"></li>
</ul>
</script>
<ul ng-app="Application" ng-controller="TreeController">
<li ng-repeat="data in tree" ng-include="'tree_item_renderer.html'"></li>
</ul>
JS:
angular.module("myApp", []).
controller("TreeController", ['$scope', function($scope) {
$scope.delete = function(data) {
data.nodes = [];
};
$scope.add = function(data) {
var post = data.nodes.length + 1;
var newName = data.name + '-' + post;
data.nodes.push({name: newName,nodes: []});
};
$scope.tree = [{name: "Node", nodes: []}];
}]);
Have a look at this fiddle
This picture below show you what I hope to attain!

jQuery sortable not working

I have a jquery accordion with selectable lists inside. When the user clicks an item, it appears in their selected items list, which is sortable. There are a number of columns that appear in their list as default columns, and each item selected shows up as green in the accordion.
My issue is that line items with two words in the sortable list are not sortable, but items with one word are. I cannot figure out why. Any thoughts?
Here's my fiddle: http://jsfiddle.net/kmbonin82/NkgC2/9/
HTML:
<h3>List 1</h3>
<ul class="list">
<li id="Country">Country</li>
<li id="Region">Region</li>
<li id="Location_Name">Location Name</li>
<li id="Location_Start">Location Start</li>
</ul>
<h3>List 2</h3>
<ul class="list">
<li id="Contract_Start">Contract Start</li>
<li id="Contract_Status">Contract Status</li>
<li id="Contract">Contract</li>
</ul>
<p id="feedback">
<span>You've selected items:</span>
<ul id="select-result">
<li id="Region">Region</li>
<li id="Location Name">Location Name</li>
<li id="Country">Country</li>
<li id="Contract Status">Contract Status</li>
</ul>
</p>
JS:
$(function () {
$(".list").selectable({
stop: function () {
var result = $("#select-result");
$(".ui-selected", this).each(function () {
$(this).css('background-color', '#669966');
$(this).css('color', '#FFFFFF');
result.append('<li id="' + $(this).text() + '">' + $(this).text() + '</li>');
sortColumns();
});
}
});
sortColumns();
});
$(function () {
$("#accordion").accordion({
collapsible: true,
autoHeight: false
});
});
$(function () {
$("#select-result li").each(function (index) {
var thisID = $(this).attr('id');
thisID = thisID.replace(/ /g, '_');
document.getElementById(thisID).style.background = '#669966';
document.getElementById(thisID).style.color = '#FFFFFF';
sortColumns();
});
});
function sortColumns() {
$(function () {
$("#select-result")
.sortable({
handle: ".handle",
over: function () {
removeIntent = false;
},
out: function () {
removeIntent = true;
},
beforeStop: function (event, ui) {
if (removeIntent == true) {
var thisID = ui.item.text();
thisID = thisID.replace(/ /g, '_');
ui.item.remove();
document.getElementById(thisID).style.background = '#FFFFFF';
document.getElementById(thisID).style.color = '#000000';
}
}
})
.find("li")
.addClass("ui-corner-all")
.prepend("<div class='handle'><span class='ui-icon ui-icon-carat-2-n-s'></span></div>");
});
}
The 'Location Name' and the 'Contract Status' are not sortable because their id values are wrong. You have space between them.
<li id="Location Name">Location Name</li>
<li id="Contract Status">Contract Status</li>
Updated Demo: http://jsfiddle.net/NkgC2/10/
Bonus:
a) the way you are pre-pending the div is not a right way. If you see your html code, after each item you select it adds an extra div for each list item
b) Instead of calling sortable() function couple times (it get calls 3 times before even selecting any item. ) use jquery 'on' method to bind api to non-existing elements.

Resources