Knockout JS - Setting table width based on an observable field - javascript

I am building a web page with a table showing transactions.
The table has a drop-down menu which is used to select the transaction type to display. A table with one row contains this drop-down menu, which needs to be aligned to show at the right edge of the transaction table. Other filter fields are present, depending on the transaction type, and these start from the left side of the table's single row.
Depending on the transaction type, the table's width changes.
I created an observable field in my view model which equals the current width of the table.
The following markup defines this layout, with only one filter - the dropdown selection of transaction type.
<fieldset id="transactionFilters">
<table data-bind="width: TransactionGridWidth">
<!-- I also tried the following:
<table data-bind="style: {width: TransactionGridWidth}">
I tried appending "px" to the width field as well, with no change.
-->
<tr>
<th style="width: 350px">
<div class="dropdown" style="margin: 10px 0 10px 15px">
<div align="right">
<span style="padding: 10px">View </span>
<button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-expanded="true">
<span id="dropdownTitle" >Type 1</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Type 1</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Type 2</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">Type 3</a></li>
</ul>
</div>
</div>
</th>
</tr>
</table>
</fieldset>
One of the following grids will be shown at a time, each with a different width:
<div id="type1TransactionsGrid" style="width: 1000px;"></div>
<div id="type2TransactionsGrid" style="width: 800px; display: none;"></div>
<div id="type3TransactionsGrid" style="width: 1200px; display: none;"></div>
The following KnockoutJS script defines the observable:
var ViewModel = {
Type1TransactionsGrid: ko.observable(),
Type2TransactionsGrid: ko.observable(),
Type3TransactionsGrid: ko.observable(),
TransactionGridWidth: ko.observable(),
OnLoad: function () {
ViewModel.TransactionGridWidth(1000);//initialisation
}
};
...//rest of the implementation
ko.applyBindings(ViewModel);
ViewModel.OnLoad();
I've got a switch-case which selects which transaction grid to display, and sets TransactionGridWidth to the current grid width, like so:
ViewModel.TransactionGridWidth(document.getElementById('Type1TransactionsGrid')).getBoundingClientRect().width);
I am certain this works, as I show the value of the field on-screen, and it tracks changes. The debugger confirms that the observable holds the correct width of the transaction grid.
No matter what I do, I can't get the table's width to change with the observable value. It works if I put in explicit size, e.g.
<table width="1000px">
TLDR:
I've got an observable variable which successfully tracks the width of the currently displayed transaction grid, but data-binding this variable to my filter table's style does not work.
What am I doing wrong?

It definitely works to use the style binding to set the width of a table. My guess is that there is some part of it you're doing wrong, but it's not clear from your question what that is.
function ViewModel() {
this.tableWidth = ko.observable();
}
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table style="border: 1px solid black" data-bind="style: {width: tableWidth() + 'px'}">
<tr>
<td>Some content</td>
</tr>
</table>
<p>
<select data-bind="value: tableWidth, options: [200, 300, 400]"></select>
</p>

Related

showing Div inside td of a table is not reactive using Vue

I have a table that the last column is a div where I have three options (View, Edit and delete). This sub menu is always hidden, but when I click in the options button that is the last column of my table, the array that I use to control what is showing is updated to true (it should be showing), but nothing happened in my page.
Here is my HTML code
<td class="kt-datatable__cell">
<span style="overflow: visible; position: relative; width: 197px;">
<center>
<div class="dropdown">
<a data-toggle="dropdown" class="btn btn-sm btn-clean btn-icon btn-icon-md" #click="toggleHover(index)"
v-bind:class="{'show': hover[index]}">
<i class="flaticon2-shield"></i>
</a>
<div v-bind:class="{'show': hover[index]}" class="dropdown-menu">
And here is my method that I call using #click
methods: {
toggleHover(index) {
this.hover[index] = !this.hover[index];
}
If I set true for a random position right after I get the data from the server, it shows, but when I try to change this by clicking, nothing happens.
It's a reactivity caveat, so you should do :
methods: {
toggleHover(index) {
this.$set(this.hover,index , !this.hover[index]);
}

show item on specific table cell on hover in angular 4

<td *ngFor="let tbh of tblH; let i=index" on-mouseover="hoveredI=i" on-
mouseleave="hoveredI=-1">{{data[tbh]}}
<div class="onHoverDiv" *ngIf="i==hoveredI">
<ul>
<li (click)="editCell(data,tbh);">
<span class="fa fa-pencil"></span>
</li>
</ul>
</div>
</td>
this my HTML code to show edit icon on hover on specific table cell but the problem is its working but its show icon in all the particular column of table cell i want show edit icon on hover in specific table cell how this to be done
Try with the following css:
li.fa-pencil {
display: none;
}
li:hover.fa-pencil {
display: inline-block;
}
you need to set one extra key is_hover into your array.set is_hover by default false.and just set below code.
you need to set like first in the component.
tblH.foreach((tbh,i)=>{tblh[i].is_hover = false})
html
<td *ngFor="let tbh of tblH; let i=index" (mouseleave)="tbh.is_hover =!tbh.is_hover" (mouseenter)="tbh.is_hover =!tbh.is_hover">{{data[tbh]}}
<div class="onHoverDiv" *ngIf="tbh.is_hover">
<ul>
<li (click)="editCell(data,tbh);">
<span class="fa fa-pencil"></span>
</li>
</ul>
</div>
</td>

Only show country subset text in bootstrap formhelpers country picker

I am using Bootstrap FormHelpers country picker and I have the following init code:
<div class="bfh-selectbox bfh-languages pull-right" data-language="es_ES" data-available="gl_ES,ca_ES,eu_ES,es_ES" data-flags="false" data-blank="false"></div>
This code generate this output:
<div class="bfh-selectbox bfh-languages pull-right" data-language="es_es" data-available="gl_ES,ca_ES,eu_ES,es_ES" data-flags="false" data-blank="false">
<input type="hidden" name="" value="es_es">
<a class="bfh-selectbox-toggle form-control" role="button" data-toggle="bfh-selectbox" href="#">
<span class="bfh-selectbox-option">Galego (Spain)</span>
<span class="caret selectbox-caret"></span></a>
<div class="bfh-selectbox-options">
<div role="listbox">
<ul role="option">
<li>
<a tabindex="-1" href="#" data-option="gl_ES">Galego (Spain)</a>
</li>
<li><a tabindex="-1" href="#" data-option="ca_ES">Català (Spain)</a></li>
<li><a tabindex="-1" href="#" data-option="eu_ES">Euskara (Spain)</a></li>
<li><a tabindex="-1" href="#" data-option="es_ES">Español (Spain)</a></li>
</ul>
</div>
</div>
That's is fine, but I would get only the subset names like "Galego", "Catalá", "Euskara", and "Español", but avoiding the append of " (Spain)" (country name). So the bootstrap select only will show the subset locale country names.
Could be this implemented easily? The only thing that I think that could work and it is very ugly is access to the DOM and remove in each li role="option" the " (Spain)" text after load the page, but I am looking for some elegant way maybe initializing bootstrap options.
It's simple if you declare it with: data-language="es" instead of es_ES
<div class="bfh-selectbox bfh-languages pull-right" data-language="es" data-available="gl_ES,ca_ES,eu_ES,es_ES" data-flags="false" data-blank="false"></div>
This is the documentation for Language Picker
This is the only tricky way that I figure out using javascript, since I think that bootstrap component doesn't allow this feature with native implementation. Writing here the solution if helps in future to someone more:
<script>
$( document ).ready(function()
{
$('.bfh-selectbox-options li a').each(function(key, value) {
//console.log($(this).text().replace(' (Spain)',''))
$(this).text($(this).text().replace(' (Spain)',''))
});
$('.bfh-selectbox-option').text($('.bfh-selectbox-option').text().replace(' (Spain)',''))
});
</script>

Drop down menu selection ditactes what form will display

I'm currently working on a project that saves details of different types of objects to a database e.g. book, webpage and journal article. To save the different attributes of these objects I am trying to get different forms to display that depend on the selection in a drop down menu.
Here's the dropdown menu:
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
Select Reference Type...
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation"><a role="menuitem" tabindex="-1" href="book.php">Book</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="journal.php">Journal</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="webpage.php">Webpage</a></li>
</ul>
</div>
How to I get a different form to load on screen without redirecting to a different page. I've been trying to do this in php but I get the feeling that php isn't the right way of going about doing this. Also, apologies in advance as I have no previous experience in Javascript, AJAX or jQuery.
Okay, so without knowing the rest of your code, I would suggest that the best option would be to have the different forms in separate documents.
For example
HTML
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
Select Reference Type...
<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<li role="presentation"><a onclick="bookinclude()" role="menuitem" tabindex="-1" href="book.php">Book</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="journal.php">Journal</a></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="webpage.php">Webpage</a></li>
</ul>
</div>
<div id="contentwrapper">
Some Initial Content Here
</div>
Javascript
function bookinclude(){
$("#contentwrapper").fadeOut(400);
setTimeout(function(){$("#contentwrapper").load("book.php").fadeIn();}, 400);
};
And remember to include Jquery!In the head of your HTML:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Basically, on the click of the book link, it will load the book.php into the contentwrapper div.
I think this is what you want? All you need to do is replicate the function, and the link, but replace the book with journal, and with webpage.
Hope this helps!
you can also keep all the 3 forms on the same page and can hide or show them on the basis of the dropdown selection.
Lets say there are 3 forms:
1. book
2. webpage
3. journal
Create forms for all three in html, and by default keep all of them hidden(for that we will use a class "display-none"), after that detect change in the dropdown on basis of whom the form populates and do action as required. Please look at the following peace of code, it might help:
<style type="text/css">
.display-none {
display: none;
}
</style>
<select id="dropdown" onchange="myFunction()">
<option value="-1">-- Select --</option>
<option value="book">Book</option>
<option value="webpage">Webpage</option>
<option value="journal">Journal</option>
</select>
<form id="book" class="display-none" method="post" action="where-you-want-to-post/book">
<input type="submit" value="Submit Book" />
</form>
<form id="webpage" class="display-none" method="post" action="where-you-want-to-post/webpage">
<input type="submit" value="Submit Webpage" />
</form>
<form id="journal" class="display-none" method="post" action="where-you-want-to-post/journal">
<input type="submit" value="Submit Journal" />
</form>
<script type="text/javascript">
function myFunction() {
var allForms = document.getElementsByTagName('form');
var dropdown = document.getElementById("dropdown");
if (dropdown.value != "-1") {
var form = document.getElementById(dropdown.value);
for (var i = 0; i < allForms.length; i++) {
allForms[i].setAttribute("class", "display-none");
}
form.setAttribute("class", "");
}
}
</script>
Demo: http://jsfiddle.net/oynjj3jn/
In order to accomplish your goal, you would need the following
A menu in your HTML page like this one. Let's say that the values of the select-list will be your PHP files, just as it's shown below
<!-- HTML -->
<p>Select reference type...</p>
<!-- This is the menu -->
<select id="menu">
<option value="book.php">Book</option>
<option value="jurnal.php">Jurnal</option>
<option value="webpage.php">Webpage</option>
</select>
<!-- This is the container for your HTML content -->
<div id="content"></div>
You'll need this snippet to make AJAX requests to your server
// JavaScript
var s = document.getElementById('menu'); // reference to the <select> menu
var c = document.getElementById('content'); // reference to the content <div>
s.onchange = function(){ // hook the change event on <select>
xhr = new XMLHttpRequest();
var url = 'your-domain/' + this.value; // here we're passing the selected value
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) { // wait for the response
c.innerHTML = xhr.responseText; // here it comes; populate the <div>
}
};
xhr.send();
};
And these are your PHP files on the server-side; they may contain any valid PHP / HTML code
// PHP
// book.php or jurnal.php or webpage.php
echo 'anything';

How to do a foreach binding using KnockoutJS in Bootstrap-themed dropdown

I'm developing a small notifications-like module, where the user can see his 5 latest activities that are logged in the DB (MSSQL). The values that I need are all there, but for some reason knockout binding is not working. Here are code snippets:
<div class="dropdown-menu toolbar pull-right" data-bind="with: layoutLogsModel">
<h3 style="border: none;">Recent activities:</h3>
<!-- "mailbox-slimscroll-js" identifier is used with Slimscroll.js plugin -->
<ul id="mailbox-slimscroll-js" class="mailbox" data-bind="foreach: layoutLogsModel.notification">
<div class="alert inbox">
<a href="javascript:void(0)">
<i class="icon-book" style="color: orange;"></i>
Some text
</a>
<br>
Some text #2
</div>
</ul>
</div>
For now, I only want to display random text for every item that is in the observableArray.
ViewModel is the following:
var layoutLogsModel = {
notification: ko.observableArray()
};
function getLastFiveActivities() {
get(apiUrl + "Logs/GetLastFiveActivities", { ClientUserID: loggedUserID }, function (data) {
layoutLogsModel.notification(data);
});
}
And every time I call this function, the list is empty (IMAGE)
(the function is called on click, and absolutely no errors are shown in the console).
What is it that I am doing wrong?
EDIT:
The thing was, I forgot to execute ko.applyBindings for that viewModel. Then, I changed the HTML to look like this:
<ul id="mailbox-slimscroll-js" class="mailbox" data-bind="foreach: notification">
<div class="alert inbox">
<a href="javascript:void(0)">
<i class="icon-user" style="color: green;"></i>
<span data-bind="text: $data"></span>
</a>
</div>
</ul>
Aslo, I modified the get function slightly, like this:
function getLastFiveActivities() {
get(apiUrl + "Logs/GetLastFiveActivities", { ClientUserID: loggedUserID }, function (data) {
layoutLogsModel.notification(data.Notification);
});
}
(changed data to data.Notification based on the MVC model property that contains the array)
After all that, the data was available immediately.
try removing the layoutLogsModel from the foreach, you are already using it with the binding "with", so eveything in that div will be part of layoutLogsModel.
<div class="dropdown-menu toolbar pull-right" data-bind="with: layoutLogsModel">
<h3 style="border: none;">Recent activities:</h3>
<!-- "mailbox-slimscroll-js" identifier is used with Slimscroll.js plugin -->
<ul id="mailbox-slimscroll-js" class="mailbox" data-bind="foreach: notification">
<div class="alert inbox">
<a href="javascript:void(0)">
<i class="icon-book" style="color: orange;"></i>
Some text
</a>
<br>
Some text #2
</div>
</ul>
</div>

Categories

Resources