Bootstrap Dropdown with MVC - Keep last selected value displayed - asp.net

I have the following Bootstrap dropdown in my Coverage MVC View. It defaults to "Active" status. When another status is selected, the associated items are shown on the page, for instance, "Past Coverage".
<div class="dropdown">
<button id="statusButton" class="btn dropdown-toggle ddlDisplay" type="button" data-toggle="dropdown">
Active
<span class="caret"></span>
</button>
<ul id="statusDropdown" class="dropdown-menu">
<li>Active</li>
<li>Past Coverage</li>
<li>Researching Now</li>
</ul>
</div>
I have the following javascript to change the html of the dropdown, so in this case it would say "Past Coverage".
$(".dropdown-menu li a").click(function () {
var selText = $(this).text();
$("#statusButton").html(selText + '<span class="caret"></span>');
This works fine, but you can only see, in this case, "Past Coverage", for a second, because then the href link is fired, the MVC Url.Action is called, the page reloads and Active is once again shown in the dropdown. How do I keep the most recent selected status in the dropdown?

You can use localStorage for storing. If you want to store in a per page session basis, then you can use sessionStorage.
Something like this should do.. Don't forget to clear the localStorage by calling localStorage.clear(); when needed.
$(".dropdown-menu li a").click(function () {
var selText = $(this).text();
$("#statusButton").html(selText + '<span class="caret"></span>');
localStorage['selText'] = selText; // store in storage
|);
$(document).ready(function() {
var selText = localStorage['selText'] || 'defaultValue';
if(selText != 'defaultValue') {
$("#statusButton").html(selText + '<span class="caret"></span>'); // Load previously selected item
}
});
I haven't really done something like this in particular so there must be a better way other than this. But this should work.

Related

Meteor delete list item with selected class

I am trying to add a delete function that if i click on a list item(template) it adds a selected class to the li. I then want be able to click a button that finds the li with a class of selected and passes the data to a meteor method that removes the data from a collection. How do i access this data.
I have tried a few ways but this is what i have so far.
sidebar.js
Template.Sidebar.events({
'click .button-collapse': function() {
console.log("here")
$(".button-collapse").sideNav();
},
'click #delete i': function() {
Meteor.call('deleteListItem', $( "li.selected" )._id);
}
})
sidebar.html
<template name="Sidebar">
<ul id="slide-out" class="side-nav fixed grey darken-3">
<li class="action-bar">
<span id="add-new" data-target="modal-add" class="modal-trigger"><i class="small material-icons">add</i></span>
<span id="save"><i class="small material-icons">note_add</i></span>
<span id="rename"><i class="small material-icons">mode_edit</i></span>
<span id="delete"><i class="small material-icons">delete</i></span>
<span data-activates="slide-out" id="close" class="button-collapse close "><i class="small material-icons right">reorder</i></span>
</li>
<!-- Load save items-->
{{#if Template.subscriptionsReady}}
{{#each userSaves}}
{{>ListItem}}
{{/each}}
{{else}}
<p>Loading</p>
{{/if}}
</ul>
<i class="material-icons">menu</i>
<!-- Modal form to add new simulator file -->
<!-- Modal Structure -->
<div id="modal-add" class="modal">
<div class="modal-content">
<h4>New Simulator</h4>
{{> quickForm collection=saves id="newSimulator" type="insert" buttonClasses="modal-action modal-close btn waves-effect waves-light" buttonContent="Add"}}
</div>
</div>
</template>
list class
Meteor.methods({
deleteListItem: function(id) {
Saves.remove(id);
}
});
You can not retrieve the ID of an object like that. Either your button has to be inside the document you're gonna remove or you have to include the _id in your HTML attributes and get that value.
So simply add data-value="{{_id}}" to your <li> in your loop and get the selected like this:
//this will retrieve the id of one selected element only
//you need to use each/forEach if you want to remove multiple
$('li.selected').attr('data-value')
EDIT:
Another solution would be using Session. Since you click on an item to select it, you can set a Session in that event
//in the click event where you select a list item
Session.set('itemId', this._id);
//in Sidebar events
'click #delete i': function() {
const itemId = Session.get('itemId');
Meteor.call('deleteListItem', itemId);
}
EDIT 2:
If you use Session solution, don't forget to remove the Session when the template is destroyed. Otherwise (for your use case) when you go to another route and come back without deleting a selected item and click the delete button, it will delete the document even though it doesn't appear to be selected.
Template.templateName.onDestroyed(function(){
Session.set('sessionName', undefined);
});

Meteor session not getting set in Template events

I want to show a button in my template which is shown or not dependent on a session value being true or false. However when I want to set the session to false in events it does not happen:
<template name="Home">
{{#if reload}}
<a class="btn btn-primary fontScale reloadBtn" href="#" id="reload"><i class="fa fa-refresh fa-lg"></i> Reload</a>
{{/if}
</template>
Template.Home.helpers({
reload: function(){
.........
(imgCount1 > imgCount) ? Session.set('more',true):Session.set('more', false);
return Session.get('more');
}
});
Template.Home.events({
......
"click #reload": function(){
Session.set('more', false);
}
});
How can I set the session variable back to false after the button had been clicked?
I guess your helper is keeping the session variable to true. When you click the button, you are setting the session variable, but not the image count.
If that's the case, just put some logging in both the click event and on the helper, and you might see one overwriting the value from the other.

Accessing data from outside events callback

<template name="SideNav">
<ul class='block-items white'>
{{#each blocks}}
<li class='block-item'>
<i class="fa fa-fw fa-folder"></i>
<i class="fa fa-fw fa-folder-open"></i>
<a href='#' class='block-item-link'>
{{name}}
...
{{/each blocks}}
</template>
Given this, I can access each block-item's id when it's clicked by doing
Template.SideNav.events({
"click .block-item": function (e, tem) {
//var blockItemId = this._id;
}
});
How can I borrow the same feature from other places, like onRendered()? Take a look at the following example:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
// How do I get blockId?
})
console.log("block item rearranged");
}
});
update is a callback function that's invoked when there was a change in the order of block items in the ul list. I need a way to iterate through all the block items and get their corresponding Mongo id's. How can I do it?
Related Documents:
The context of "this" in Meteor template event handlers (using Handlebars for templating)
Update: the "Meteor way"
If you are looking for how Blaze gets this data context for events and helpers, it turns out there is a magical Blaze.getData() function which takes a Blaze view or a DOM object and returns its data context. As far as I could tell by looking at the code, it seems to be the tool Blaze uses for providing data contexts to helpers and events.
So in your case, you could use:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
var context = Blaze.getData(blockItem.get(0));
var blockId = context._id;
})
console.log("block item rearranged");
}
});
Original answer
An easy way to get the id of a document when working with DOM manipulation (other than blaze events) is to explicitly set it as an attribute in your template, such as:
<template name="SideNav">
<ul class='block-items white'>
{{#each blocks}}
<li class='block-item' id='{{_id}}'>
<i class="fa fa-fw fa-folder"></i>
<i class="fa fa-fw fa-folder-open"></i>
<a href='#' class='block-item-link'>
{{name}}
...
{{/each blocks}}
</template>
This way, you can just fetch the id using jquery's attr method:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
var blockId = blockItem.attr('id');
})
console.log("block item rearranged");
}
});

Why does my click event not fire when I add each blocks into my template to iterate through a collection (Meteor)

The event fires only when I remove the each blocks. What the event does is apply a vertical accordion slide down transition on an element. What I want to do is add the same slide down transition to all my documents when they are displayed in my views.
Right now, when I add an each block to iterate through my collection and display all the documents from my collection, the slide down event stops working.
Here's my template:
<template name="auctionsList">
<div class="container">
<div id='cssmenu'>
<ul>
{{#each auctions}}
{{>auction}}
{{/each}}
</ul>
</div> <!-- end cssmenu -->
</div><!-- end container -->
{{#if isReady}}
{{#if hasMoreauctions}}
<a class="load-more btn btn-default center-block text-uppercase" id="loadMore" href="#" style="margin-top:10px;">Load More</a>
{{/if}}
{{else}}
<div class="loading">{{>spinner}}</div>
{{/if}}
</template>
<template name="auction">
<li class='has-sub'>
<a href='#'>
<div class="auction-image">
<img src="brand_logos/DominosPizza.png" class="img-responsive" height="200" width="200">
</div>
{{> durationLeft}}
</a>
<ul>
<li><a href='#'>
<span>Sub Product</span></a></li>
</ul>
</li>
</template>
Here's my rendered/helper
Template.auctionsList.rendered = function () {
$('#cssmenu li.has-sub>a').on('click', function(){
$(this).removeAttr('href');
var element = $(this).parent('li');
if (element.hasClass('open')) {
element.removeClass('open');
element.find('li').removeClass('open');
element.find('ul').slideUp();
}
else {
element.addClass('open');
element.children('ul').slideDown();
element.siblings('li').children('ul').slideUp();
element.siblings('li').removeClass('open');
element.siblings('li').find('li').removeClass('open');
element.siblings('li').find('ul').slideUp();
}
});
}
Template.auctionsList.helpers({
auctions: function () {
return Template.instance().userauctions();
}
});
Template.auctionsList.events({
'click #cssmenu li.has-sub>a' : function(event, template) {
$(this).removeAttr('href');
var element = $(this).parent('li');
if (element.hasClass('open')) {
element.removeClass('open');
element.find('li').removeClass('open');
element.find('ul').slideUp();
}
else {
element.addClass('open');
element.children('ul').slideDown();
element.siblings('li').children('ul').slideUp();
element.siblings('li').removeClass('open');
element.siblings('li').find('li').removeClass('open');
element.siblings('li').find('ul').slideUp();
}
}
});
You should move this from rendered to events. $('#cssmenu li.has-sub>a').on('click', function(){ }
Put the event within the auction template where your <li> tag exists.
Updated
Couple of things based on the gists you published:
1) you should try not use script tags directly in the template - i havent seen this often if at all. Move all this code to
Template.accordion.rendered = function(){ //here };
or better make it work in auctionsList because then its not duplicated x times for every each iteration.
But what would be even better is not to have the 'on' event at all. You should use a meteor event... like you mentioned in your earlier post. Meteor events have access to 'this' which is the current context item.
I would try put it in a template event on the master auctionsList template and later on worry about how it will work with the sub templates.
2) I dont think you need to add everything into another template like you have, the accordion template doesnt really need to exist, you can probably get away with putting it in the auction template (consider using even auctions to do the click event because if you do it that way your js snippet wont be repeated x times per post listing.You only need this once..
3) When you create the li in the auction template give it an ID at that point
<li id={{new accordion code in auction template}}>
You can then reference this id on your template click event. If you are new to meteor do yourself a favor and do the following in a click event to better understand what is going on (you will most likely find the ID you need within one of the values - most likely this:
Template.YourTemplate.events({
'click any button in your each': function(event,bl,value)
{
console.log(event);
console.log(bl);
console.log(value);
//and most importantly
console.log(this);
}
});
I know its not "an answer" but i hope it leads you in the right direction.

How to get part of html content inserted in a Meteor template if the content is not in the page already

I am using Meteor 0.7.0.1 with Spark and I have the following template that used to popover content, and the template is inserted at each post items.
<template name="postLinks">
<a href="#" id="ui-popover-container-{{id}}" class="popover-list-trigger dropdown-toggle" data-toggle="dropdown">
<i class="icon-calendar"></i>
</a>
{{#if poppedUp}}
<div id="link-popover-wrapper" style="display:none">
<ul class="link-popover">
{{#each linkOptions}}
<li><a tabindex="-1" class="link-action" id="link-{{value}}" href="#">{{label}}</a>
</li>
{{/each}}
</ul>
</div>
{{/if}}
</template>
I want to print the div "link-popover-wrapper" only once the first time the template loaded. Subsequent template inserts in post items the div won't inserted so only one hidden div is in the page. I handled it using a template variable in following way.
var _poppeUp = true;
Template.postLiks.helpers({
poppeUp : function () {
if (_poppeUp) {
_poppeUp = false;
return true;
}
return false;
}
});
It is working for the first time the page is loaded and only one instance of the div "link-popover-wrapper" is in the page. The problem is when a post is updated and page is re-rendered the template variable still set to false and the div is not printed in the page. I wanted to reset that template variable when a page is re-rendered.
Is there a way to overcome this issue in Meteor ?
Just add code that does the opposite on page render:
Template.postLinks.rendered = function() {
if (!_poppedUp)
_poppedUp = true;
You didn't ask, but this strikes me as an odd way to implement this. Rather than {{#if poppeUp}}, why not {{#with getFirstLinkPopoverWrapper}} and then define a getFirstLinkPopoverWrapper helper that returns just the one link-popover-wrapper div that you want shown? Then you never need to worry about re-renders or tracking some variable.
EDIT: Alternate implementation:
You could simply use jQuery to tell you whether or not an element of id link-popover-wrapper already exists on the page:
Template.postLinks.helpers({
poppedUp: function() {
return $("#link-popover-wrapper").length !== 0;
}
}
That's it. If no such element exists, the length of the jQuery object is zero and the statement evaluates as false and false is returned. Otherwise true is returned and your template adds the element.

Resources