Keep toggle hide/show after refresh page [duplicate] - javascript

I have three toggle buttons and I want to keep toggle state after refresh page.I read many things but dont know how to use them in my case.
This is buttons and divs
<button class="badge badge-danger mb-4 d-flex left" type="button" data-toggle="collapse" data-target="#personal-data" aria-expanded="false" aria-controls="personal-data"></button>
<button class="badge badge-danger mb-4 mr-md-4 ml-md-4" type="button" data-toggle="collapse" data-target="#email-change" aria-expanded="false" aria-controls="email-change"></button>
<button class="badge badge-danger mb-4" type="button" data-toggle="collapse" data-target="#user-history" aria-expanded="false" aria-controls="user-history"></button>
<div class="collapse" id="personal-data">
<div class="form-group col-12">
<div class="col-12">
<div class="collapse" id="email-change">
<div class="col-12">
<div class="collapse" id="user-history">

Use can use below way to keep state after a refresh.
Cookie
LocalStorage
Both of these can store client-side data which will preserve your state.
Provide each collapse element a unique id across the website so there'll be no room for conflict. So based on user action collapse or un-collapses an element you'll update state in storage. Now using bootstrap event and API, you can collapse or un-collapses an element based on storage state.
Here is a working demo:
https://jsfiddle.net/c1ovt5g4/
<button class="badge badge-danger left" type="button" data-toggle="collapse" data-target="#personal-data" aria-expanded="false" aria-controls="personal-data">Personal Data</button>
<button class="badge badge-danger " type="button" data-toggle="collapse" data-target="#email-change" aria-expanded="false" aria-controls="email-change">Email Change</button>
<button class="badge badge-danger" type="button" data-toggle="collapse" data-target="#user-history" aria-expanded="false" aria-controls="user-history">User History</button>
<div class="collapse" id="personal-data"> PERSONAL DATA</div>
<div class="collapse" id="email-change"> EMAIL CHANGE</div>
<div class="collapse" id="user-history">USER HISTORY</div>
$(".collapse").on("hidden.bs.collapse", function() {
localStorage.setItem("coll_" + this.id, false);
});
$(".collapse").on("shown.bs.collapse", function() {
localStorage.setItem("coll_" + this.id, true);
});
$(".collapse").each(function() {
if (localStorage.getItem("coll_" + this.id) == "true") {
$(this).collapse("show");
}
});

I tweaked Object's answer to remove the key from localstorage if hidden. From what I could find, there isn't a need to check if the key exists before attempting to remove. This reduces the amount of items being kept in localstorage.
$(document).ready(function () {
//If shown.bs.collapse add the unique id to local storage
$(".collapse").on("shown.bs.collapse", function () {
localStorage.setItem("coll_" + this.id, true);
});
//If hidden.bs.collaspe remove the unique id from local storage
$(".collapse").on("hidden.bs.collapse", function () {
localStorage.removeItem("coll_" + this.id);
});
//If the key exists and is set to true, show the collapsed, otherwise hide
$(".collapse").each(function () {
if (localStorage.getItem("coll_" + this.id) == "true") {
$(this).collapse("show");
}
else {
$(this).collapse("hide");
}
});
});

Related

Vue Object not updating with axios POST request

<template>
<div>
<div class="dropdown d-inline-block ml-2">
<button type="button" class="btn btn-sm btn-dual" id="page-header-notifications-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-on:click="MarkAllAsRead($event)">
<i class="si si-bell"></i>
<span class="badge badge-danger badge-pill" v-if="CountUnread(notifications)">{{ CountUnread(notifications) }}</span>
</button>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right p-0 border-1 font-size-sm" aria-labelledby="page-header-notifications-dropdown">
<div class="p-2 bg-primary text-center">
<h5 class="dropdown-header text-uppercase text-white">Notifications</h5>
</div>
<ul class="nav-items mb-0" style="overflow-y:scroll; height:500px;">
<!-- notifications should have been updated by axios but they never appear -->
<li v-for="notification of notifications">
<div v-if="notification.length">
<notification v-bind:notification="notification[0]"></notification>
</div>
<div v-else>
<notification v-bind:notification="notification"></notification>
</div>
</li>
<div class="p-2 border-top" v-if="hasMore">
<a class="btn btn-sm btn-light btn-block text-center" href="javascript:void(0)" v-on:click="loadMoreNotifications($event)">
<i class="fa fa-fw fa-arrow-down mr-1"></i> Load More..
</a>
</div>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
props:[
'user'
],
data: function() {
return{
notificationsIndex:0,
notifications:[],
hasMore:1
}
},
methods: {
loadNotifications: function(){
var data = {
index: this.notificationsIndex
};
axios.post('/notifications/getAll',data).then( response => {
if(response.data){
if(this.notifications.length==0){
this.notifications=response.data;
console.log(this.notifications);//data fetched here successfully
}
else{
this.notifications.push.apply(this.notifications,response.data);
}
}
else{
this.hasMore = 0;
}
});
console.log(this.notifications);//couldn't find data, just observer object
},
loadMoreNotifications: function(event){
event.preventDefault();
this.notificationsIndex++;
this.loadNotifications();
},
CountUnread: function(notifications){
var count=0;
for(var i=0;i<notifications.length;i++){
if(notifications[i].read_at == null){
count++;
}
}
return count;
},
HasNotification: function(notification){
list = this.notifications.filter(item => {
return item.id == notification.id;
});
return list.length
}
},
created: function(){
this.loadNotifications();
window.Echo.private('App.User.' + this.user.id)
.notification((notification) => {
if(this.HasNotification){
this.notifications.unshift(notification);
}
});
}
}
</script>
And notifications object has nothing in html template as well.
Note: This same code works fine on all pages where I have this only instance of vue. On another page (localhost/horizon)(using laravel horizon package and updating it's layout.blade.php ) where there are two instances of vue, one for notifications and other of Laravel/Horizon, this request returns nothing.
The problem here as #cbaconnier mentioned is that you're using an async function and not waiting for the result.
The console.log() that's failing is due to the fact that it's executed before the post request is retrieved (that's why you're receiving an observer).
The same happens in your created method.
try taking all the code that's dependant on the received notifications into the .then() callback of the axios call.
The problem here was, I was using a bootstrap shipped with app theme I was using and when I installed Horizon and updated Horizon layout.blade.php file according to my customisations, it broke this piece of code because it was using some other bootstrap version and once I removed the bootstrap from the horizon require('bootstrap'); in one of it's app.js file, everything worked fine.

Javascript: Change button text change after click

I have a simple question about changing the text of a button after the user clicks it.
I would like the button click to cause the text to toggle between two values: "More" and "Less". Note that before the first click, it must have the value "More" and after the click the value "Less":
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
More
</button>
<div class="collapse" id="collapseExample">
<p>Test</p>
</div>
This can be achieved using vanilla javascript via the following:
/*
Fetch the buttom element
*/
const button = document.body.querySelector('[data-target="#collapseExample"]');
/*
Add click event listener where we will provide logic that updates the button text
*/
button.addEventListener('click', function() {
/*
Update the text of the button to toggle beween "More" and "Less" when clicked
*/
if(button.innerText.toLowerCase() === 'less') {
button.innerText = 'More';
}
else {
button.innerText = 'Less';
}
});
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
More
</button>
<div class="collapse" id="collapseExample">
<p>Test</p>
</div>
Basically, you could add an onclick event to the button referencing to a function:
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample" onclick="changeText()">
More
</button>
Then, you prepare the function to change the text:
function changeText () {
if (this.innerText == "More") { // check if text inside is "More"
this.innerText == "Less"; // If so, change to "Less"
} else {
this.innerText == "More";
}
}

Bootstrap Collapse - close other on click

I am using Bootstrap/Collapse for these 3 buttons. You can see it live here - those 3 yellow buttons. When I click on the first button and then on the second button, I want to close the first div by clicking the second. Can you help me how can I do it?
here's some supporting code:
<a class="btn btn-primary btn-sm" data-toggle="collapse" href="#price" aria-expanded="false" aria-controls="price">Podle ceny</a>
<a class="btn btn-primary btn-sm" data-toggle="collapse" href="#manufacturers" aria-expanded="false" aria-controls="manufacturers">Podle značky</a>
<a class="btn btn-primary btn-sm" data-toggle="collapse" href="#13" aria-expanded="false" aria-controls="13">Podle velikosti</a>
<ul>
<li data-type="price" data-base-type="price" data-id="price" data-seo-name="price" data-inline-horizontal="0" data-display-live-filter="0" data-display-list-of-items="" class="mfilter-filter-item mfilter-price mfilter-price collapse" id="price">
...
</li>
<li data-type="checkbox" data-base-type="manufacturers" data-id="manufacturers" data-seo-name="manufacturers" data-inline-horizontal="0" data-display-live-filter="0" data-display-list-of-items="" class="mfilter-filter-item mfilter-checkbox mfilter-manufacturers collapse" id="manufacturers">
...
</li>
<li data-type="checkbox" data-base-type="option" data-id="13" data-seo-name="13o-velikost" data-inline-horizontal="0" data-display-live-filter="0" data-display-list-of-items="" class="mfilter-filter-item mfilter-checkbox mfilter-option mfilter-options collapse" id="13">
...
</li>
</ul>
One of the way to achieve the desired output would be by using jquery. I have implemented the similar feature by using script written here. You can run on your system and look for the effect.
`<script>` `src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js</script>`
`<script>
$(document).ready(function(){
$("#button1").click(function(){
$('#button1').html("<p>"+"hello"+"</p>");
})
$("#button2").click(function(){
$('#button2').html("<li>"+"hello"+"</li>");
$('p').hide();
})
$("#button3").click(function(){
$('#button3').html("<li>"+"hello"+"</li>");
$('#button2').find('li').hide();
})
})
</script>`
Attach three button with id button1 ,button2 and button3 inside body tag of html code .
Now to get the exact functionality replace the class name and id to achieve the exact feature.

AngularJS - How to maintain checked ticket ids of a table

I have a table containing next & previous pages. I am able to navigate to next/previous pages using next & previous buttons.
On previous & next page actions on call(controller methods) I am pushing checked ticket ids by pushing in an array $scope.checkedTicketIds
angular.forEach($scope.tickets, function(ticket) {
if(ticket.checked) {
$scope.checkedTicketIds.push(ticket.id);
}
});
HTML code is
<div class="mail-tools tooltip-demo m-t-md">
<div class="btn-group pull-right">
<button ng-click="previousPage()" ng-disabled="previousPageBtnDisabled()" class="btn btn-white btn-sm"><i class="fa fa-arrow-left"></i></button>
<button ng-click="nextPage()" ng-disabled="nextPageBtnDisabled()" class="btn btn-white btn-sm"><i class="fa fa-arrow-right"></i></button>
</div>
<div class="input-group">
<div class="input-group-btn" dropdown>
<button ng-disabled="ticketsChecked()" class="btn btn-white dropdown-toggle pull-left" dropdown-toggle type="button">{{'ACTIONS' | translate}} <span class="caret"></span></button>
<ul class="dropdown-menu pull-left">
<li ng-repeat="(key, value) in actions"><a ng-click="convertAction(key)">{{key | translate}}</a></li>
</ul>
</div>
</div>
</div>
In controller on clicking previous page button calling method
$scope.previousPage = function() {
angular.forEach($scope.tickets, function(ticket) {
if(ticket.checked) {
$scope.checkedTicketIds.push(ticket.id);
}
});
$scope.ticketsUpdatedQueryCriteria.page = --$scope.page;
Tickets.query($scope.ticketsUpdatedQueryCriteria).then(function(tickets) {
$scope.tickets = tickets.data;
$scope.ticketsPageData = tickets.cursor;
});
};
How to pop/remove id on uncheck & I wanted to maintain checked ticket ids for further bulk actions, like change status of one/more tickets. How can I do this?
I implement an example on jsbin, using an independent checked list.
Please, look at:
http://jsbin.com/rudifa/3/
Hope I help you.

Convert razor enumdropdownlistfor to bootstrap button group dropdown

I have a razor syntax enumdropdownlist for displaying either active/inactive status.
#Html.EnumDropDownListFor(model => model.Status, new { #class = "btn btn-default btn-lg dropdown-toggle" })
I want to use a button group drop down with glyphs like I have below but don't know how to get my model value 'model.Status' to set the value of the button group drop down.
$(document).ready(function() {
$('#item1').on('click', function() {
$('#item0').text('Active');
});
$('#item2').on('click', function() {
$('#item0').text('Not Listed');
});
});
<div class="btn-group">
<button id="item0" type="button" class="btn btn-default">Action</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li id="item1">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>Active
</li>
<li id="item2">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>Not Listed
</li>
</ul>
</div>
I don't care if I use html or razor, I just want to use the boostrap button drop down with glyphs and I want to be able to set the enumerated view model value active/inactive (Status) when the page loads.
Although the Bootstrap dropdown buttons look similar to a select list, their functionality is vastly different. I wouldn't recommend trying to use a Bootstrap dropdown button as a replacement for a select list if you need to actually post the "selected" item.
If you're just looking for a more stylistic and visually appealing alternative to a traditional select control, take a look at something like Select2, and while the look is pleasant enough out of the box, there's also a project that styles it to fit even better with the rest of Bootstrap.
If you're dead set on using Bootstrap dropdown buttons, you've got a lot of work ahead of you. You'll need to set up some JavaScript that will read the information from the select element and dynamically create the Boostrap dropdown button based on that, while hiding the original select. Then, you'll need to map over all the events such as a click on one of the items in the dropdown so that it selects the same item in the actual select element. You'll also have to account for highlighting the item in the dropdown that corresponds with the selected option in the select list, etc. If you run into specific problems while writing all that code, you can ask additional questions here as necessary, but providing you with all the code you'll need here is far beyond the scope of StackOverflow.
You can try to enumerate through enum values and put them in page, please notice the Html.HiddenFor from the end, we will use it to store the selected Status.
<div class="btn-group">
<button id="item0" type="button" class="btn btn-default">Action</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
#{
var values = Enum.GetValues(typeof(Status));
for(int i=0; i < values.Count; i++)
{
var status = (Status)values[i];
<li id="item#(i+1)" class="select-status" data-status="#values[i]">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>#status.ToString()
</li>
}
}
</ul>
</div>
#Html.HiddenFor(model => model.Status)
After we create the html we have to update the selected Status in Html.HiddenFor to persist when a POST is performed.
$(document).ready(function() {
$('.select-status').click(function(){
$('#Status').val($(this).data('status')); // update the status in hidden input
});
#for(int i=0; i < values.Count; i++)
{
<text>
$('#item#(i+1)').on('click', function() {
$('#item0').text('#status.ToString()');
});
</text>
}
});
HTML snippet example:
$(document).ready(function() {
$('.select-status').click(function(){
$('#Status').val($(this).data('status')); // update the status in hidden input
});
$('#item1').on('click', function() {
$('#item0').text('Active');
});
$('#item2').on('click', function() {
$('#item0').text('Not Listed');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<div class="btn-group">
<button id="item0" type="button" class="btn btn-default">Action</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li id="item1" class="select-status" data-status="1">
<span class="glyphicon glyphicon-ok" aria-hidden="true"></span>Active
</li>
<li id="item2" class="select-status" data-status="2">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>Not Listed
</li>
</ul>
</div>
<br />
Visible Status just for test
<input type="text" id="Status" value="1" />
Note: The code may have some errors but the logic/flow is the same.
In .cshtml file
<script>
myModelStatus = '#Model.Status';
</script>
#Html.EnumDropDownListFor(model => model.Status, new { #class = "btn btn-default btn-lg dropdown-toggle" })
more html here...
In your js file
$(document).ready(function() {
var status = myModelStatus;
$('#item1').on('click', function() {
$('#item0').text('Active');
});
$('#item2').on('click', function() {
$('#item0').text('Not Listed');
});
});
You are listening for click events on the li element rather than on the anchor tag
You should stop event propagation by using event.preventDefault() method.

Categories

Resources