how to implement dynamic breadcrumb - javascript

I want to implement dynamic breadcrumb and really dont know how do i go about it. Cant find much examples on internet. Please see attached image where i have added breadcrumb. The code for it as below
<div style="font-size: 10px;">
<ul class="breadcrumb">
<li>
Home <span class="divider">></span>
</li>
<li>
<li><a id="navObject" href="../AgrProduct/Index.aspx" class="active" >Search</a></li>
</ul>
</div>
Currently i have just 2 level in breadcrumb as Home and Search. when i click on button Search it will show me list of products and when i select one on product the breadcrumb should show as Home > Search > Product. I am also attaching image of what happens when i click on Search button
Please let me know how should i go about it. I am really stuck. I use knockout,jquery.

Well, if you created a breadcrumb view model:
var breadCrumbViewModel = function()
{
var self = this;
self.breadCrumbs = ko.observableArray();
self.addCrumb = function(url, text, active)
{
self.breadCrumbs.push({ 'url': url, 'text': text, 'active': active });
}
self.reset = function()
{
self.breadCrumbs.removeAll();
}
}
And then use it something like this (I've not tested this, so there may be some errors in it, but the idea should be good!)
<ul class="breadcrumb" data-bind="foreach: breadCrumbViewModel.breadCrumbs">
<li>
<a data-bind="attr: { href: url }, text: text, css: { active: active }"></a> <span data-bind="visible: $index < breadCrumbViewModel.breadCrumbs - 1" class="divider">></span>
</li>
</ul>
You would set it up in the function called whenever you navigate to a "page" within your SPA:
function()
{
breadCrumbViewModel.reset();
breadCrumbViewModel.addCrumb('#/Home', 'Home');
breadCrumbViewModel.addCrumb('#/Product/:id', 'Search', true);
}
Don't forget to bind the model the the html element for knockout to do its stuff.
I'm using the example code for sammy.js for the navigation, though I will admit that I haven't used sammy.js before, I've got a custom implementation of navhistory.js from the Microsoft Big Shelf SPA example. But that should be enough to give you a head start on it. I'm assuming that you actually want this to be a SPA, despite having actual URLs in your links that would take you off to another page.

Related

how to add class 'active' to nav item whose href is in the location.pathname

I'm trying to build on top of a Jekyll template to build a blog style site. I'm currently in the process of writing and styling the navigation, which is giving me a couple of problems. Using the answer to this question I've managed to add the class active on the current page, but here are the issues that still need ironing out:
First, all the 'tabs' are active when the page loads, not just the 'home' tab:
Second, the relevant 'tab' is no longer active when the url goes deeper than the first level of navigation. The url of the below screenshot is [baseurl]/reviews/[name-of-post], but the reviews 'tab' is not active:
I'm not sure how to approach the first problem, but for the second I think I will need to search the location.pathname for the relevant href, but I need to look further into this. Will update as necessary, but I've been playing around with this for ages with no luck so thought I'd post in the meantime.
Below are the code snippets for the relevant parts:
Side navigation HTML (written in Liquid)
<nav id="side-nav">
<ul class="nav-items-list">
<li id="nav-item"><i class="fas fa-home"></i></li>
{% for page in site.pages %}
<li id="nav-item">
<a href="{{ site.baseurl }}/{{ page.title | downcase }}/">
<i class="{{ page.icon }}"></i>
</a>
</li>
{% endfor %}
</ul>
</nav>
Example page (YAML frontmatter)
---
layout: page
title: Reviews
permalink: /reviews/
icon: "fas fa-star-half-alt"
---
jQuery
$(function(){
var current = location.pathname;
$('#nav-item a').each(function(){
var $this = $(this);
if($this.attr('href').indexOf(current) !== -1){
$this.addClass('active');
}
})
})
That should hopefully be enough, but if any more code is needed, please let me know. All the code is also available on GitHub, where the project is also hosted on GitHub Pages.
Thanks in advance.
Jamie
The following should theoretically work:
// Compute the closest (2-part) base path from the current location
var basePath = '/' + window.location.pathname.split('/', 3).filter(Boolean).join('/') + '/';
// Add `active` class to the corresponding link if any
$('#nav-item a[href="' + basePath + '"]').addClass('active');
The first line basically takes the first 2 parts of the pathName, so:
if the URL is /glossd/, it yields /glossd/,
if the URL is /glossd/reviews/, it yields /glossd/reviews/,
if the URL is /glossd/reviews/something/, it still yields /glossd/reviews/.

Vue #click doesn't work on an anchor tag with href present

EDIT: I forgot to clarify, what I'm looking for is to know how to write an anchor tag with the href attribute present but that when the element is clicked, the href should be ignored and the click handler should be executed.
I'm currently using Vue 1 and my code looks like:
<div v-if="!hasPage(category.code)">
<div>
<template v-for="subcategoryList in subcategoryLists[$index]" >
<ul>
<li v-for="subcategory in subcategoryList"v-on:click.stop="test()">
<a :href="subcategory.url">{{subcategory.label}}</a>
</li>
</ul>
</template>
</div>
</div>
What i'm trying to do is present the user with some buttons that represent my site's categories, some of this buttons will lead the user to another page and other will toggle a dropdown with a list of subcategories, when clicking these subcategories you will be taken to the subcategory's page.
These would be pretty simple but these buttons need to be tracked by Google Tag Manager so that's why I used the #click attribute to call a function and ignore the href attribute. This doesn't work, I have tried #click.prevent, #click.stop, #click.stop.prevent and none of these work.
The thing is that if I remove the href attribute, the #click method works great but an SEO requirement is to have href attributes on every link.
Any help would be appreciated.
As #dan-oswalt specified in the comments, you have to add the click event on the same element as the href. The reason it did not work the time you tried is most likely because you tried with #click.stop which only stops propagation, not the default action. (Redirect to the link). What you want is to prevent the browser to redirect the user: #click.prevent
new Vue({
el: '#app',
data: {
subcategoryList: Array(10).fill({
url: 'http://google.com',
label: 'http://google.com'
})
},
methods: {
test(event) {
event.target.style.color = "salmon"
}
}
})
Vue.config.devtools = false
Vue.config.productionTip = false
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<main id="app">
<template>
<ul>
<li v-for="subcategory in subcategoryList">
<a :href="subcategory.url" v-on:click.prevent="test($event)">{{subcategory.label}}</a>
</li>
</ul>
</template>
</main>

Passing values to a controller

I am struggling with passing all the data I need to a controller in MVC. The code is as follows:
<td><a href=#Url.Action("AddCourseToStudentPlan", "Users", new {
courseID = c.CourseId, userID = user.UserId, semNum = num}) title="Add Course
to Semester" >"Here"</a></td>
(currently num is defined as var num = 1;, which of course won't work.)
The course ID's and userID's are passing fine. these values are coming from a ViewBag essentially.
However, semNum is dependent on something entirely different:
<ul class="nav nav-tabs" id="Semtabs">
#{ var year = plan.CatalogYear; }
<li class="active">Fall #year</li>
#{ year += 1; }
<li class="">Spring #year</li>
<li class="">Fall 2014</li>
<li class="">Spring 2015</li>
<li class="">Fall 2015</li>
<li class="">Spring 2016</li>
<li class="">Fall 2016</li>
...
The intended output is that when the user clicks on one of the tabs, they see a list of courses that they have added, and are able to add courses to this tab by clicking on the link in the code previous code block. Therefore, clicking on a tab should change the value of num in the #Url.Action() method. But of course I can't do this because C# is server side.
So the problem is, how am I able to pass some variable semNum (which is determined client-side) to the #Url.Action() method after the page loads?
There are multiple ways to do it. This one is fairly intuitive and will not cause syntax errors in Visual Studio.
Create a URL template with the info you know.
When the link is clicked, look at the current state of the tabs.
Use that information to complete the URL.
Navigate as desired.
<!-- define a link/button, but don't set the URL -->
<a id="add-url-button">Add Course to Semester</a>
<!-- your existing tabs -->
<ul class="nav nav-tabs" id="Semtabs">
<li>Tab 1</li>
<li class="active">Tab 2</li>
<!-- etc. -->
</ul>
<script>
// Create a URL template
// It sounds like semNum is the only value that needs to vary,
// but you can create a template with multiple placeholders.
// We pass zero for semNum so that routes will still match without
// conflicting with a real semester number.
var addUrlTemplate = '#Url.Action("AddCourseToStudentPlan", "Users", new { courseID = c.CourseId, userID = user.UserId, semNum = 0 }';
// jQuery here for brevity (will work fine with vanilla JS)
var addButton = $("#add-url-button"),
tabs = $("#Semtabs");
addButton.click(function(){
// determine the selected tab by interrogating the list of tabs
var activeTab = tabs.find("li.active"),
semesterNumber = activeTab.attr("semester-numer");
// Construct the complete URL. Depending on the URL, you may need
// a smarter regex. Be sure that there is no chance of accidentally
// replacing the wrong value.
var addUrl = addUrlTemplate.replace(/0$/, semesterNumber);
// navigate as desired
window.location.href = addUrl;
));
</script>

ng-repeat, do not update table after data was updated?

I have a table that is populating with ng-repeat, and I also have navigation button that change table data. Before I had custom filter on the data in html file, like so:
ng-repeat="car in carList | filter:tableFilter"
Even so it worked, it slowed my website, a lot. So now I am updating my table data in my controller. But there is another problem, ng-repeat do not want to update. So no matter how much I will update my data, the table will be still the same.
How can I fix that?
Here is my ng-repeat:
<tbody>
<tr ng-repeat="car in sortedCarList">
....
Here is my nav-bar:
<section class="tab" ng-controller="TablePanelCtrl as panel">
<ul class="nav nav-pills car-navigation">
<li ng-class="{ active: panel.isSelected(1)}">
<a href ng-click="panel.selectTab(1); initCarList(1); resetActiveRow(); formattedTable(2); hideTypeBox()">Sort by Reviews</a>
</li>
<li ng-class="{ active: panel.isSelected(2)}">
<a href ng-click="panel.selectTab(2); initCarList(2); resetActiveRow() formattedTable(2); hideTypeBox()">Sort by Rating</a>
</li>
</ul>
initCarList() changes the data according to tab number.
formattedTable() filters table data according to filter values that can be changes by user.
UPDATE:
my formatting function:
$scope.formattedTable = function(index){
$scope.initCarList(index);
$scope.sortedCarList = [];
var carlistLength = $scope.carList.length;
for (var i=0;i<carlistLength;i++){ // just check every row if values passes user requirements
var rowBool = $scope.tableFilter($scope.carList[i]);
if (rowBool){
$scope.sortedCarList.push($scope.carList[i]);
}
}
}
While I agree with cerbrus that we need to see a bit more of your code, I'll take a stab in the dark : you call formattedTable(2) in both tabs, which means that your filtering never changes.

Angular - linking to a ngInclude partial

I have followed the documentation on setting up ngInclude and have it working (loading in HTML partials) and changing the partial when a select option is changed.
$scope.templates = [
{ name: 'Overview', url: 'partials/project/overview.html' },
{ name: 'Tasks', url: 'partials/project/tasks.html' }
];
$scope.template = $scope.templates[0];
----
<div ng-controller="Tasks">
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
<section ng-include="template.url"></section>
</div>
However, I don't want to use a select menu to navigate. I want to use an unordered list. I tried using ngHref, but that doesn't seem to work. I can't find much documentation on binding an element to change an ngInclude partial, but maybe I'm searching for the wrong thing.
Any help on how I could use anchor tags to change the partial being loaded in on click would be great.
Here's the structure I was playing around with:
<ul class="header-menu">
<li><a ng-modal="template" ng-href="{{template[0]}}" class="selected">Overview</a></li>
<li><a ng-modal="template" ng-href="{{template[1]}}">Tasks</a></li>
</ul>
You just need to store the path to your template, and change it based on an action in your list. ngHref isn't related here, because it would load the template itself which isn't what you want.
See this demo plunker:
HTML:
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="template in templates">
{{template.name}}
<button ng-click="selectTemplate(template)">Go!</button>
</li>
</ul>
{{selectedTemplate}}
<div ng-include="selectedTemplate"></div>
</body>
Controller:
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.templates=[{
name:'First Template',
url:'template1.html'
}
,{
name:'Second Template',
url:'template2.html'
}
]
$scope.selectedTemplate=$scope.templates[0].url;
$scope.selectTemplate=function(template){
$scope.selectedTemplate=template.url;
}
});
But I really suggest you to check out to check out ui-router, as it sounds like you are trying to implement some tab system, and changing states for your app, and ui-router does that perfectly.

Categories

Resources