I am using Bootstrap cards on a page, where I want those cards to be sorted using up and down arrows. Every card has arrows in its header, to move it up or down in the layout. But of course, when it gets moved to the top, the up arrow should be gone, likewise for when it hits the bottom.
I've tried using if statements in this style:
// Result: Is never executed.
if(!$(card).find('.sort-down')) {}
// Result: Is always executed.
if($(card).not(':has(.sort-down)') {}
Where $(card) is the div containing the complete card that is being moved.
For example, my complete "move down" code block.
$(document).on('click', '.sort-down', function(e) {
e.preventDefault();
let card = $(this).closest('.card');
let sort_id = $(card).attr('data-sort');
let next_sort_id = Number(sort_id) + 1;
$('[data-sort]').each(function(index, value) {
if($(value).attr('data-sort') == next_sort_id) {
$(value).after($(card));
$(value).attr('data-sort', sort_id);
$(card).attr('data-sort', next_sort_id);
// Change buttons
if($(card).attr('data-sort') == sortCount - 1) {
$(card).find('.sort-down').remove();
if(!$(card).find('.sort-up')) {
// Insert up arrow
}
} else {
if(!$(card).find('.sort-up')) {
// Insert up arrow
}
if(!$(card).find('.sort-down')) {
// Insert down arrow
}
}
if($(value).attr('data-sort') == 0) {
$(value).find('.sort-up').remove();
if(!$(value).find('.sort-down')) {
// Insert down arrow
}
} else {
if(!$(value).find('.sort-down')) {
// Insert down arrow
}
if(!$(value).find('.sort-up')) {
// Insert up arrow
}
}
return false;
}
});
});
A little bit of the HTML so you can get an idea what classes/attributes my jQuery is selecting.
<div class="card mb-3" data-sort="0">
<div class="card-header">
Tekstveld
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-down"><i data-feather="arrow-down" width="16" height="16"></i></button>
</div>
<div class="card-body p-0">
<div id="editor"></div>
</div>
</div>
As I usually overcomplicate things, and get the result of it not even working, I'm hoping you could help me with either a simple or more advanced working solution of getting this done.
Using data-sort attribute as a sorting index could be more useful for "Global" sorting or filtering. Like when we click on one button to sort them all based on that property value.
But here, a less complicated alternative is to use jQuery default methods like : next(),prev(),closest(),insertAfter(),insertBefore()
$( document ).ready(function() {
setButtons();
$(document).on('click', '.sort-down', function(e) {
var cCard = $(this).closest('.card');
var tCard = cCard.next('.card');
cCard.insertAfter(tCard);
setButtons();
resetSort();
});
$(document).on('click', '.sort-up', function(e) {
var cCard = $(this).closest('.card');
var tCard = cCard.prev('.card');
cCard.insertBefore(tCard);
setButtons();
resetSort();
});
function resetSort(){
var i=0;
$('.card').each(function(){
//$(this).data('sort',i);
$(this).attr("data-sort", i);
i++;
});
}
function setButtons(){
$('button').show();
$('.card:first-child button.sort-up').hide();
$('.card:last-child button.sort-down').hide();
}
function resetSort(){
var i=0;
$('.card').each(function(){
//$(this).data('sort',i);
$(this).attr("data-sort", i);
i++;
});
}
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="card mb-3" data-sort="0">
<div class="card-header">
Tekstveld
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-down"><i class="fas fa-caret-down"></i></button>
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-up"><i class="fas fa-caret-up"></i></button>
</div>
<div class="card-body p-0">
<div class="editor"></div>
</div>
</div>
<div class="card mb-3" data-sort="1">
<div class="card-header">
Voorbeeld
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-down"><i class="fas fa-caret-down"></i></button>
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-up"><i class="fas fa-caret-up"></i></button>
</div>
<div class="card-body p-0">
<div class="editor"></div>
</div>
</div>
<div class="card mb-3" data-sort="2">
<div class="card-header">
Lorem ipsum
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-down"><i class="fas fa-caret-down"></i></button>
<button type="button" class="btn btn-sm btn-primary float-right mr-1 sort-up"><i class="fas fa-caret-up"></i></button>
</div>
<div class="card-body p-0">
<div class="editor"></div>
</div>
</div>
</div>
[UPDATE] : The setButtons() function would hide the non functional buttons when the div reach the limit.
Notice that I added another function resetSort() to reorder those data-sort values. Just in case, you need it for global sorting.
Not sure how to do this, but I would like to pass a string as an argument into ng-click and then us it as a conditional in the function. so something like this?
<div class="row">
<div class="col-md-12 text-center mb-5">
<div class="btn-group">
<button class="btn btn-primary" ng-click=""><span class="ion-plus-circled mr-2"></span>New</button>
<button class="btn btn-outline-primary" ng-click="filter_emails('inbox')"><span class="ion-archive mr-2"></span>Inbox</button>
<button class="btn btn-outline-primary" ng-click=""><span class="ion-paper-airplane align-middle mr-2"></span>Shielded</button>
</div>
</div>
</div>
and then in my controller:
$scope.filter_emails = function(category) {
if (category == "inbox") {
$scope.grouped = group(inbox($scope.emails));
}
else {
$scope.grouped = group($scope.emails);
}
}
This is not working or I obviously wouldn't be posting the question, so what would the correct approach to this?
If you want to pass a string enclose it within quotes
ng-click="filter_emails('inbox')"
I have a strongly typed view in which I am looping over some objects from a database and dispaying them in a jumbobox with two buttons in it. When I click one of the buttons I have a modal popping up. I'd like to have somewhere in this modal the name and the id of the corresponding object, but I do not really know how to do this. I am a bit confused where to use c# and where javascript. I am a novice in this, obviously.
Can someone help?
This is the code I have so far. I don't have anything in relation to my question, except the code for the modal :
#model IEnumerable<eksp.Models.WorkRole>
#{
ViewBag.Title = "DisplayListOfRolesUser";
}
<div class="alert alert-warning alert-dismissable">You have exceeded the number of roles you can be focused on. You can 'de-focus' a role on this link.</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var dataJSON;
$(".alert").hide();
//make the script run cuntinuosuly
$.ajax({
type: "POST",
url: '#Url.Action("checkNumRoles", "WorkRoles")',
dataType: "json",
success: successFunc,
error: errorFunc
});
function successFunc(data, status) {
if (data == false) {
$(".alert").show();
$('.btn').addClass('disabled');
//$(".btn").prop('disabled', true);
}
}
function errorFunc() {
alert('error');
}
});
</script>
#foreach (var item in Model)
{
<div class="jumbotron">
<h1>#Html.DisplayFor(modelItem => item.RoleName)</h1>
<p class="lead">#Html.DisplayFor(modelItem => item.RoleDescription)</p>
<p> #Html.ActionLink("Focus on this one!", "addWorkRoleUser", new { id = item.WorkRoleId }, new { #class = "btn btn-primary btn-lg" })</p>
<p> <button type="button" class="btn btn-default btn-lg" data-toggle="modal" data-target="#myModal">Had role in the past</button> </p>
</div>
}
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">#Html.DisplayFor(modelItem => item.RoleName)//doesn't work</h4>
</div>
<div class="modal-body">
<p>Some text in the modal.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>
</div>
</div>
</div>
I think your confusing the server side rendering of Razor and the client side rendering of the Modal. The modal cannot access your Model properties as these are rendered server side before providing the page to the user. This is why in your code <h4 class="modal-title">#Html.DisplayFor(modelItem => item.RoleName)//doesn't work</h4> this does not work.
What you want to do is capture the event client side in the browser. Bootstrap allows you to achieve this by allowing you to hook into events of the Modal. What you want to do is hook into the "show" event and in that event capture the data you want from your page and supply that to the Modal. In the "show" event, you have access to the relatedTarget - which is the button that called the modal.
I would go one step further and make things easier by adding what data you need to the button itself as data-xxxx attributes or to DOM elements that can be easily access via JQuery. I have created a sample for you based on what you have shown to give you an idea of how it can be achieved.
Bootply Sample
And if needed... How to specify data attributes in razor
First of all
you will need to remove the data-toggle="modal" and data-target="#myModal" from the button, as we will call it manually from JS and add a class to reference this button later, your final button will be this:
<button type="button" class="btn btn-default btn-lg modal-opener">Had role in the past</button>
Then
In your jumbotron loop, we need to catch the values you want to show later on your modal, we don't want to show it, so we go with hidden inputs:
<input type="hidden" name="ID_OF_MODEL" value="#item.WorkRoleId" />
<input type="hidden" name="NAME_OF_MODEL" value="#item.RoleName" />
For each information you want to show, you create an input referencing the current loop values.
Now you finally show the modal
Your document.ready function will have this new function:
$('.modal-opener').on('click', function(){
var parent = $(this).closest('.jumbotron');
var name = parent.find('input[name="NAME_OF_MODEL"]').val();
var id = parent.find('input[name="ID_OF_MODEL"]').val();
var titleLocation = $('#myModal').find('.modal-title');
titleLocation.text(name);
// for each information you'll have to do like above...
$('#myModal').modal('show');
});
It simply grab those values we placed in hidden inputs.
Your final code
#model IEnumerable<eksp.Models.WorkRole>
#{
ViewBag.Title = "DisplayListOfRolesUser";
}
<div class="alert alert-warning alert-dismissable">You have exceeded the number of roles you can be focused on. You can 'de-focus' a role on this link.</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var dataJSON;
$(".alert").hide();
//make the script run cuntinuosuly
$.ajax({
type: "POST",
url: '#Url.Action("checkNumRoles", "WorkRoles")',
dataType: "json",
success: successFunc,
error: errorFunc
});
function successFunc(data, status) {
if (data == false) {
$(".alert").show();
$('.btn').addClass('disabled');
//$(".btn").prop('disabled', true);
}
}
function errorFunc() {
alert('error');
}
$('.modal-opener').on('click', function(){
var parent = $(this).closest('.jumbotron');
var name = parent.find('input[name="NAME_OF_MODEL"]').val();
var id = parent.find('input[name="ID_OF_MODEL"]').val();
var titleLocation = $('#myModal').find('.modal-title');
titleLocation.text(name);
// for each information you'll have to do like above...
$('#myModal').modal('show');
});
});
</script>
#foreach (var item in Model)
{
<div class="jumbotron">
<input type="hidden" name="ID_OF_MODEL" value="#item.WorkRoleId" />
<input type="hidden" name="NAME_OF_MODEL" value="#item.RoleName" />
<h1>#Html.DisplayFor(modelItem => item.RoleName)</h1>
<p class="lead">#Html.DisplayFor(modelItem => item.RoleDescription)</p>
<p> #Html.ActionLink("Focus on this one!", "addWorkRoleUser", new { id = item.WorkRoleId }, new { #class = "btn btn-primary btn-lg" })</p>
<p> <button type="button" class="btn btn-default btn-lg" data-toggle="modal" data-target="#myModal">Had role in the past</button> </p>
</div>
}
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">#Html.DisplayFor(modelItem => item.RoleName)//doesn't work</h4>
</div>
<div class="modal-body">
<p>Some text in the modal.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>
</div>
</div>
I am trying to replicate the following HTML code by using only Javascript (no jQuery).
I want the buttons to appear as a group,but it looks like they are being appended individually.
I've read up on bootstrap button groups (http://getbootstrap.com/components/#btn-groups) and the btn-group classs is being called on the html. So therefore my javascript DOM manipulation is incorrect.
Can someone help me to understand why my buttons are not appearing correctly? Please note that this is only a snippet of the entire code. the HTML elements are nested in a "row" div and "container" div.
HTML
<div>
<div class="btn-group btn-group-lg">
<button type="button" class="btn btn-default">Left</button>
<button type="button" class="btn btn-default">Middle</button>
<button type="button" class="btn btn-default">Right</button>
</div>
</div>
Javascript
var divTwo = document.createElement('div');
row.appendChild(divTwo);
col.appendChild(divTwo);
var btnGroupFour = document.createElement('div');
btnGroupFour.className = 'btn-group btn-group-lg';
divTwo.appendChild(btnGroupFour);
var btnLeft = document.createElement('button');
var textLeft = document.createTextNode('Left');
btnLeft.appendChild(textLeft);
btnLeft.className = 'btn btn-default';
var btnMiddle = document.createElement('button');
var textMiddle = document.createTextNode('Middle');
btnMiddle.appendChild(textMiddle);
btnMiddle.className = 'btn btn-default';
var btnRight = document.createElement('button');
var textRight = document.createTextNode('Right');
btnRight.appendChild(textRight);
btnRight.className = 'btn btn-default';
btnGroupFour.appendChild(btnLeft);
btnGroupFour.appendChild(btnMiddle);
btnGroupFour.appendChild(btnRight);
jsfiddle link:
https://jsfiddle.net/bchang89/eh7uhs43/2/
You can use cloneNode() on the parent element .btn-group and set it to a deep copy. Deep copy will create a copy of the target node as well as it's descendants. The only limitation is that it will not copy any event listeners added to either the target node or it's descendants.
// Collect all .btn-group into a NodeList (btnGrp)
var btnGrp = document.querySelectorAll('.btn-group');
// Determine the last .btn-grp by using the .length property -1
var lastGrp = btnGrp.length - 1;
// Reference the index in the btnGrp NodeList
var tgt = btnGrp[lastGrp];
// Create a clone of tgt and set the parameter to true for deep copy
var dupe = tgt.cloneNode(true);
// Append the clone to the body or any other element you wish.
document.body.appendChild(dupe);
EDIT
// Appendinding to `.container` since it looks better and makes more sense.
var box = document.querySelector('.container');
box.appendChild(dupe);
Fiddle
Snippet
var box = document.querySelector('.container');
var btnGrp = document.querySelectorAll('.btn-group');
var lastGrp = btnGrp.length - 1;
var tgt = btnGrp[lastGrp];
var dupe = tgt.cloneNode(true);
box.appendChild(dupe);
.btn-default {
color: #007aff;
background-color: #fff;
border-color: #007aff;
}
.btn-default:hover,
.btn-default:focus,
.btn-default:active {
color: #fff;
background-color: #007aff;
border-color: #007aff;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row">
<div class="col-md-12">
<div>
<div class="btn-group">
<button type="button" class="btn btn-default">1</button>
<button type="button" class="btn btn-default">2</button>
<button type="button" class="btn btn-default">3</button>
<button type="button" class="btn btn-default">4</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default">5</button>
<button type="button" class="btn btn-default">6</button>
<button type="button" class="btn btn-default">7</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-default">8</button>
</div>
</div>
<hr>
<div>
<div class="btn-group btn-group-lg">
<button type="button" class="btn btn-default">Left</button>
<button type="button" class="btn btn-default">Middle</button>
<button type="button" class="btn btn-default">Right</button>
</div>
</div>
</div>
</div>
</div>
I really need help for this thing i'm working on.
Basically I have 4 charts rendered by chartjs. I've made 4 buttons, that simply show or hide the desired DIV. I'm pretty sure it's works on jQuery side, but I'm not so skilled to understand what's happening here on Chart.js side.
This is a demo https://jsfiddle.net/ttum6ppu/
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<p>
<button type="button" class="btn btn-default btn-xs stanza_button" id="stanza" style="display:none;">Per stanza</button>
<button type="button" class="btn btn-primary btn-xs stanza_selected" id="stanza"><i class="fa fa-eye"></i> Per stanza</button>
<button type="button" class="btn btn-default btn-xs settimanale_button" id="settimanale">Andamento settimanale</button>
<button type="button" class="btn btn-primary btn-xs settimanale_selected" id="settimanale" style="display:none;"><i class="fa fa-eye"></i> Andamento settimanale</button>
<button type="button" class="btn btn-default btn-xs mensile_button" id="mensile">Andamento mensile</button>
<button type="button" class="btn btn-primary btn-xs mensile_selected" id="mensile" style="display:none;"><i class="fa fa-eye"></i> Andamento mensile</button>
<button type="button" class="btn btn-default btn-xs annuo_button" id="annuo">Andamento annuo</button>
<button type="button" class="btn btn-primary btn-xs annuo_selected" id="annuo" style="display:none;"><i class="fa fa-eye"></i> Andamento annuo</button>
</p>
<script>
$(document).ready(function(){
$("#stanza").click(function(){
$(".stanza, .stanza_selected, .settimanale_button, .mensile_button, .annuo_button").show();
$(".settimanale, .mensile, .annuo, .stanza_button, .settimanale_selected, .mensile_selected, .annuo_selected").hide();
});
$("#settimanale").click(function(){
$(".settimanale, .settimanale_selected, .stanza_button, .mensile_button, .annuo_button").show();
$(".stanza, .mensile, .annuo, .stanza_selected, .settimanale_button, .mensile_selected, .annuo_selected").hide();
});
$("#mensile").click(function(){
$(".mensile, .mensile_selected, .stanza_button, .settimanale_button, .annuo_button").show();
$(".stanza, .settimanale, .annuo, .stanza_selected, .settimanale_selected, .mensile_button, .annuo_selected").hide();
});
$("#annuo").click(function(){
$(".annuo, .annuo_selected, .stanza_button, .settimanale_button, .mensile_button").show();
$(".stanza, .settimanale, .mensile, .stanza_selected, .settimanale_selected, .mensile_selected, .annuo_button").hide();
});
});
</script>
<div style="width: 50%">
<div style="height:70%;" class="stanza">
<canvas id="canvas" height="100px;"></canvas>
</div>
<div style="height:70%; display: none;" class="settimanale">
<canvas id="canvas2" height="100px;"></canvas>
</div>
<div style="height:70%; display: none;" class="mensile">
<canvas id="canvas3" height="100px;"></canvas>
</div>
<div style="height:70%; display: none;" class="annuo">
<canvas id="canvas4" height="100px;"></canvas>
</div>
</div>
<script>
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
var barChartData = {
labels : ["January","February","March","April","May","June","July"],
datasets : [
{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,0.8)",
highlightFill: "rgba(220,220,220,0.75)",
highlightStroke: "rgba(220,220,220,1)",
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
},
{
fillColor : "rgba(151,187,205,0.5)",
strokeColor : "rgba(151,187,205,0.8)",
highlightFill : "rgba(151,187,205,0.75)",
highlightStroke : "rgba(151,187,205,1)",
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
}
]
}
window.onload = function(){
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive : true
});
var ctx = document.getElementById("canvas2").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive : true
});
var ctx = document.getElementById("canvas3").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive : true
});
var ctx = document.getElementById("canvas4").getContext("2d");
window.myBar = new Chart(ctx).Bar(barChartData, {
responsive : true
});
}
</script>
</body>
The first chart is displayed correctly, but when You press the second button it shows nothing.
Thank You in advance
In my view a better solution is to modify the DOM to replace the canvas element, so you can redraw it with your new data :
var canvas_html = '<canvas id="canvas" height="100px;"></canvas>';
var drawChart = function(data) {
// reinit canvas
$('#canvas_container').html(canvas_html);
// redraw chart
var ctx = document.getElementById("canvas").getContext("2d");
window.myBar = new Chart(ctx).Bar(data, {
responsive : true
});
};
I have made an update of your fiddle so you can see the result.
This is fiddly, think it's because your using Chart.js which creates the charts using iframes which are never fun to work with. Without forcing a page reload I dont think you're going to be able to do it. The canvas is being drawn at 0px height and width on the hidden charts so just changing their parents divs display using jQuery to block isn't going to cut the mustard.
I've updated your fiddle so that clicking on each button shows each chart separately but the only thing I couldnt fix was hiding the last three charts on page load. Hopefully this is something that you can work with.
I've removed display: none from the charts
I had same issue and solved it by looking at visibility of container div, if div is visible render chart otherwise do nothing. so on switch tab call function to render chart, by that time div should be visible. here is sample code,
if ($(".canvas-holder2").is(":visible")) {
window['myDoughnut'] = new Chart($("#chart-area")[0]
.getContext("2d"))
.Doughnut(data, {
responsive: true,
animateScale: true
});
window['myDoughnut'].update();
}