Knockout click binding with mapping plugin - javascript

I am trying to use the click binding to increment and subtract a value in a text binding by one. I am not sure how to reference myNumber.
html:
<a data-bind="click: increment">
<i class="fa fa-chevron-up"> </i>
</a>
<div data-bind="text: myNumber"></div>
<a data-bind="click: subtract">
<i class="fa fa-chevron-down"> </i>
</a>
js:
<script type="text/javascript">
function increment(result){
result.myNumber ++;
}
function subtract(result){
result.myNumber --;
}
$.getJSON("/app/api/", function(result) {
function viewModel() {
return ko.mapping.fromJS(result);
};
ko.applyBindings(new viewModel());
})
.error(function () { alert("error"); });
</script>

You don't increment an observable as if it were a number. It is a setter/getter.
Also, the functions you bind need to be part of the viewmodel. You can do that inside your getJSON callback before applyBindings.
vm = {
myNumber: ko.observable(3),
increment: function(result) {
result.myNumber(result.myNumber() + 1);
},
subtract: function(result) {
result.myNumber(result.myNumber() - 1);
}
};
ko.applyBindings(vm);
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<a href="#" data-bind="click: increment">
<i class="fa fa-chevron-up"> </i>
</a>
<div data-bind="text: myNumber"></div>
<a href="#" data-bind="click: subtract">
<i class="fa fa-chevron-down"> </i>
</a>

Related

jQuery Remember toggleClass status in list

I have a function:
function toggle(event) {
$(`#${event.target.id}`).toggleClass('fa-power-on fa-power-off');
}
I also have a list of buttons:
<i id="id1" onclick="toggle($event)"></i>
<i id="id14" onclick="toggle($event)"></i>
<i id="id12" onclick="toggle($event)"></i>
<i id="id17" onclick="toggle($event)"></i>
<i id="id18" onclick="toggle($event)"></i>
<i id="id1w" onclick="toggle($event)"></i>
I need the status of the toggleClass icon to be remembered for each.
Either by localStorage or id's and status all in an object and then saved on localstorage or other.
The <i></i> list is dynamic so I cannot hardcode it.
How can I do this?
Consider the following example.
$(function() {
function toggle(el) {
$(el).toggleClass("fa-power-on fa-power-off");
}
function getPowerStatus(selector) {
var results = [];
$(selector).each(function(i, el) {
var key = $(el).attr("id");
var val = $(el).hasClass("fa-power-on");
var item = {};
item[key] = val;
results.push(item);
});
return results;
}
function saveStatus(stats) {
localStorage.setItem("status", JSON.stringify(stats));
}
function getStatus() {
return JOSN.parse(localstorage.getItem("status"));
}
$("i[id^='id']").click(function(e) {
toggle(this);
var status = getPowerStatus("i[id^='id']");
console.log(status);
saveStatus(status);
});
});
.fa-power-off {}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<i id="id1" class="fas fa-power-off"></i>
<i id="id14" class="fas fa-power-off"></i>
<i id="id12" class="fas fa-power-off"></i>
<i id="id17" class="fas fa-power-off"></i>
<i id="id18" class="fas fa-power-off"></i>
<i id="id1w" class="fas fa-power-off"></i>
This created functions to toggle, gather the status of each, set, and get those status to Local Storage.
Not sure what Icon Set you're using, but Font-Awesome does not have a fa-power-on. Which would mean you'd want to toggle a different class.
$(function() {
function toggle(el) {
$(el).toggleClass("on");
}
function getPowerStatus(selector) {
var results = [];
$(selector).each(function(i, el) {
var key = $(el).attr("id");
var val = $(el).hasClass("on");
var item = {};
item[key] = val;
results.push(item);
});
return results;
}
function saveStatus(stats) {
localStorage.setItem("status", JSON.stringify(stats));
}
function getStatus() {
return JOSN.parse(localstorage.getItem("status"));
}
$("i[id^='id']").click(function(e) {
toggle(this);
var status = getPowerStatus("i[id^='id']");
console.log(status);
saveStatus(status);
});
});
.fa-power-off {
border-radius: 50%;
}
.fa-power-off.on {
background: black;
color: white;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<i id="id1" class="fas fa-power-off"></i>
<i id="id14" class="fas fa-power-off"></i>
<i id="id12" class="fas fa-power-off"></i>
<i id="id17" class="fas fa-power-off"></i>
<i id="id18" class="fas fa-power-off"></i>
<i id="id1w" class="fas fa-power-off"></i>
Now you can Click them on or off. Each time click event happens, it toggle the class and updates the saved status. You can then get the status when the page loads and re-apply the on class as needed.

Call action on button outside function

I wrote a script where I add items to individual sections on the page. I will show you this by the example of one particular section. The problem appears with the c-grid-box, which is responsible for the fadeOut of the parent div. The anonymous function responsible for this action must be called outside of the diva addition function (otherwise I would have to add a function to each call that misses the target). For this I wrote something like this, although it still does not work - what could be the reason here?
function showModal(type) {
switch(type) {
case "title":
$(".overlay").fadeIn("slow");
$("#modal-inputs").html('<input type="text" placeholder="Title..." class="param-title" name="param-title" /><input type="text" placeholder="Description..." class="param-description" name="param-description" /><input type="submit" class="add-btn" id="insert-title" value="Insert" />');
break;
}
}
$("#add-text").on("click", function() {
showModal("title");
$("#insert-title").on("click", function() {
title = $(".param-title").val();
description = $(".param-description").val();
$('#section-title').append('<div class="grid-1-5"><div class="grid_box">Delete</i><p class="grid-box-title">'+title+'</p><p>'+description+'</p></div></div>');
$(".overlay").fadeOut("slow");
});
});
$(".grid_box").on("click", ".c-grid-box", function() {
alert("foo bar");
});
.overlay {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="add-text">
<i class="fa fa-align-justify" aria-hidden="true"></i>
<p>Add <i class="fa fa-angle-right" aria-hidden="true"></i></p>
</button>
<section class="add-box" id="section-title">
</section>
<div class="overlay">
<div class="modal-box">
<p class="modal-title"><i class="fa fa-cogs" aria-hidden="true"></i>Settings
<i class="fa fa-times" aria-hidden="true"></i>
</p>
<div id="modal-inputs">
</div>
</div>
</div>

Backbone sort collections by click on non template elements

I want to sort my backbone collections by clicking non backbone template elements
In brief , i have 2 Sorting options named "Sort by date" and "Sort by name". when i click these elements i need to sort my collection in my backbone view
View template :
<ul>
<li>Sort By date</li>
<li>Sort By name</li>
</ul>
<script type="foo/bar" id='videos-thumbnail'>
<div class="col-md-4">
<div class="video-thumbnail-item">
<div style="background-image:url(recenty_added/recentlyadded2.jpg);" class="video-thumbnail"> </div>
<div class="video-details">
<div class="video-title text-purple uppercase"><%= title %></div>
<div class="video-date"><%= date %></div>
</div>
<div class="video-thumbnail-checkbox"> <span class="custom-checkbox">
<input type="checkbox" class="playlist-checkbox" name="addto-playlist[]">
</span>
<% if (is_rights_managed== true) { %>
<div class="checkbox-label-light">RM</div>
<% } else {%>
<div class="checkbox-label-light"></div>
<% } %>
</div>
<div class="video-thumbnail-options"> <span title="Download" class="option-parts"> <i class="fa fa-download"></i> </span> <span title="Edit" class="option-parts"> <i class="fa fa-pencil"></i> </span> <span title="More Information" class="option-parts"> <i class="fa fa-info-circle"></i> </span> <span title="View Details" class="option-parts"> <i class="fa fa-search"></i> </span> <span title="Add to Clipbins" class="option-parts"> <i class="fa fa-folder-open"></i> </span> <span title="Add to Cart" class="option-parts"> <i class="fa fa-cart-plus"></i> </span> <span title="Contact me about this Clip" class="option-parts"> <i class="fa fa-envelope"></i> </span> </div>
</div>
</div>
</script>
<div class="row" id="thumbnail_target"> </div>
App :
//backbone & underscore
$(function() {
var Videos = Backbone.Model.extend();
var VideoList = Backbone.Collection.extend({
model: Videos,
url: 'https://api.myjson.com/bins/4mht3'
});
var videos = new VideoList();
var VideoView = Backbone.View.extend({
el: "#thumbnail_target",
template: _.template($('#videos-thumbnail').html()),
render: function(eventName) {
_.each(this.model.models, function(video){
var videoTemplate = this.template(video.toJSON());
$(this.el).append(videoTemplate);
}, this);
return this;
},
});
var videosView = new VideoView({model: videos});
videos.fetch({
success: function() {
videosView.render();
videoslistView.render();
}
});
});
Am newbie to backbone and underscore, am not sure how to make this work
Example fiddle : Fiddle
Since you have access to collection outside view, you can simply use jquery to bind an event handler for the <li>, which updates the collections comparator and sorts it. Then have the view re-render itself when a sort event occurs on the collection.
for the demo I'm using string and number types of sort attributes so that I can directly set it as comparator. You should write a custom comparator function that handles sorting based on different types of arguments like string, number, date etc. Updated fiddle
//backbone & underscore
$(function() {
var Videos = Backbone.Model.extend();
var VideoList = Backbone.Collection.extend({
model: Videos,
url: 'https://api.myjson.com/bins/4mht3'
});
var videos = new VideoList();
var VideoListView = Backbone.View.extend({
el: "#thumbnail_target",
template: _.template($('#videos-thumbnail').html()),
initialize: function() {
this.listenTo(this.collection, 'sort', this.render);
},
render: function(eventName) {
this.$el.empty();
_.each(this.collection.models, function(video) {
var videoTemplate = this.template(video.toJSON());
this.$el.append(videoTemplate);
}, this);
return this;
},
});
var videosView = new VideoListView({
collection: videos
});
videos.fetch({
success: function(collection) {
videosView.render();
}
});
$('#sortBy').on('click', 'li', function() {
var category = $(this).text().split('Sort By ')[1];
videos.comparator = category;
videos.sort();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>
<ul id="sortBy">
<li>Sort By average</li>
<li>Sort By title</li>
</ul>
<script type="foo/bar" id='videos-thumbnail'>
<div class="col-md-4">
<div class="video-thumbnail-item">
<div style="background-image:url(recenty_added/recentlyadded2.jpg);" class="video-thumbnail"></div>
<div class="video-details">
<div class="video-title text-purple uppercase">
<%=t itle %>
</div>
<div class="video-date">
<%=d ate %>
</div>
</div>
<div class="video-thumbnail-checkbox"> <span class="custom-checkbox">
<input type="checkbox" class="playlist-checkbox" name="addto-playlist[]">
</span>
<% if (is_rights_managed==t rue) { %>
<div class="checkbox-label-light">RM</div>
<% } else {%>
<div class="checkbox-label-light"></div>
<% } %>
</div>
<div class="video-thumbnail-options"> <span title="Download" class="option-parts"> <i class="fa fa-download"></i> </span> <span title="Edit" class="option-parts"> <i class="fa fa-pencil"></i> </span> <span title="More Information" class="option-parts"> <i class="fa fa-info-circle"></i> </span>
<span
title="View Details" class="option-parts"> <i class="fa fa-search"></i>
</span> <span title="Add to Clipbins" class="option-parts"> <i class="fa fa-folder-open"></i> </span> <span title="Add to Cart" class="option-parts"> <i class="fa fa-cart-plus"></i> </span> <span title="Contact me about this Clip" class="option-parts"> <i class="fa fa-envelope"></i> </span>
</div>
</div>
</div>
</script>
<div class="row" id="thumbnail_target"></div>
Looks like you want global vent for in-app events
$(function() {
var channel;
channel = _.extend({}, Backbone.Events);
$('.some-sort-dy-date-element').on('click', function() {
channel.trigger('app:sort', {sortBy: 'date'});
});
$('.some-sort-dy-name-element').on('click', function() {
channel.trigger('app:sort', {sortBy: 'name'});
});
// rest logic
});
Your VideoList collection should listen to channel event like that (example for initialize):
var VideoList = Backbone.Collection.extend({
initialize: function initialize() {
this.listenTo(channel, 'app:sort', function someSortLogic() {
this.trigger('your.app.ns.videos.SORTED');
});
}
});
var VideoView = Backbone.View.extend({
initialize: function initialize() {
this.listenTo(this.collection, 'your.app.ns.videos.SORTED', this.render);
}
});

Cannot get vars displayed in my 'template' using Handlebars.js correctly

I have a Handlebars script that I am trying to get to iterate through an object to my 'template' below. Even though I can see the 'badNodes' in the object (an object when i do a console.log(row) it doesn't ever pass to the template and all I see is a blank entry next to address in the view/template.
Can anyone suggest what I may have done wrong - P.S I am new to Handlebars.js
<script class="template" type="text/html">
<div class="badNodesContainer">
{{#row}}
<div class="hash{{badNodes.hash}} help-tip">
<p>
<strong>Address: </strong>{{badNodes.address}}</br>
</p>
</div>
{{/row}}
</div>
</script>
// latter part of ajax request
.done(function (data, result, jqXHR) {
var checkinData = JSON.parse(data).data;
var rows = [];
//_.templateSettings.variable = "badNode";
var source = $("script.template").html();
var template = Handlebars.compile(source);
$.each(checkinData, function (index, row) {
row.badNodesHTML = "";
var AB_action_login = '<a class="btn btn-default btn-sm" style="width:70px;text-align:left;" target="_blank" href="http://asite.com/app/login.php?username=' + row.user + '&hash=' + row.signature + '"><i class="fa fa-external-link"></i> App</a>';
if (row.postid == null) {
var AB_action_order = '<a class="btn btn-default btn-sm hidden" disabled="disabled" style="width:70px;text-align:left;" target="_blank" href="http://www.mysite.co.uk/wp-admin/post.php?post=' + row.postid + '&action=edit"><i class="fa fa-external-link"></i> Order</a>';
} else {
var AB_action_order = '<a class="btn btn-default btn-sm" style="width:70px;text-align:left;" target="_blank" href="http://www.mysite.co.uk/wp-admin/post.php?post=' + row.postid + '&action=edit"><i class="fa fa-external-link"></i> Order</a>';
}
row.AB_login = AB_action_login;
row.AB_order = AB_action_order;
row.AB_actions = AB_action_login + AB_action_order;
if (row.badNodes.length) {
$.each(row.badNodes, function (idx, badNode) {
badNode.address.toString()
badNode.address = /:(.+)/.exec(badNode.address)[1];
row.badNodesHTML += template(badNode);
row.AB_actions;
});
}
}
);
You are accessing the object via #row inside your template even though the object you pass into the template looks like this:
{
hash: 'some hash',
address: 'some address'
}
So, in order to bind it try to access it by key instead like this:
<script class="template" type="text/html">
<div class="badNodesContainer">
<div class="hash{{hash}} help-tip">
<p>
<strong>Address: </strong>{{address}}</br>
</p>
</div>
</div>
</script>
Also, assuming that badNodes is an array of bad nodes, you could use each in your declaration when you pass row to the template directly. Try this:
<script class="template" type="text/html">
<div class="badNodesContainer">
{{#each badNodes}}
<div class="hash{{hash}} help-tip">
<p>
<strong>Address: </strong>{{address}}</br>
</p>
</div>
{{/each}}
</div>
</script>
I suggest you prepare a javascript object that has the exact shape and form you would like and then pass it to the template. You are formatting the output in an $.each loop and pass each row individually which could get messy from an organizational perspective. Also, you are creating html inside your javascript for the button which you could put in the template as well. Then, all you have to do is pass one row object to the template that has all required information.
A refactored version could look like this:
<style media="screen">
.btn-zabs {
width:70px;
text-align:left;
}
</style>
<script type="text/javascript">
.done(function (data, result, jqXHR) {
var checkinData = JSON.parse(data).data;
var rows = [];
var source = $("script.template").html();
var template = Handlebars.compile(source);
var $container = $("#parent-of-badNodesContainer");
$.each(checkinData, function (index, row) {
if (row.badNodes.length) {
$.each(row.badNodes, function (idx, badNode) {
badNode.address.toString()
badNode.address = /:(.+)/.exec(badNode.address)[1];
});
}
});
$container.html(template(checkinData));
});
</script>
<script class="template" type="text/html">
<a class="btn btn-default btn-sm btn-zabs" target="_blank" href="http://asite.com/app/login.php?username={{user}}&hash={{signature}}"><i class="fa fa-external-link"></i> App</a>
<div class="badNodesContainer">
{{#each badNodes}}
<div class="hash{{hash}} help-tip">
<p>
<strong>Address: </strong>{{address}}</br>
</p>
</div>
{{/each}}
</div>
{{#if postid}}
<a class="btn btn-default btn-sm btn-zabs hidden" disabled="disabled" target="_blank" href="http://www.mysite.co.uk/wp-admin/post.php?post={{postid}}&action=edit"><i class="fa fa-external-link"></i> Order</a>
{{else}}
<a class="btn btn-default btn-sm btn-zabs" target="_blank" href="http://www.mysite.co.uk/wp-admin/post.php?post={{postid}}&action=edit"><i class="fa fa-external-link"></i> Order</a>
{{/if}}
</script>
Note, I put the button templates in an arbitrary spot. I'm sure you would want to re-organize where they belong. This is for demonstration only.

Boot strap button group change jQuery

Im starting to learn JavaScript/jQuery and have the code below that works but there must be some shorter code to write for this simple function.
The function:
Font awesome icon to show and change when i choose access level in the boot strap button group.
$(document).ready(function() {
$("#access").html(' Alla');
$("#accessIcon").addClass('fa-globe');
$('#access_input').val(0);
});
/*
' access
' 0 = all
' 1 = friends
' 2 = private
*/
$(".access").click(function(e) {
var accessId = $(this).attr('id');
if (accessId == 0) {
//alert("Alla = "+ accessId);
$("#access").html(' Alla');
$("#accessIcon").removeClass('fa-group');
$("#accessIcon").removeClass('fa-eye');
$("#accessIcon").addClass('fa-globe');
$('#access_input').val(accessId);
} else if (accessId == 1) {
//alert("Vänner = "+ accessId);
$("#access").html(' Vänner');
$("#accessIcon").removeClass('fa-globe');
$("#accessIcon").removeClass('fa-eye');
$("#accessIcon").addClass('fa-group');
$('#access_input').val(accessId);
} else if (accessId == 2) {
//alert("Privat = "+ accessId);
$("#access").html('Privat');
$("#accessIcon").removeClass('fa-globe');
$("#accessIcon").removeClass('fa-group');
$("#accessIcon").addClass('fa-eye');
$('#access_input').val(accessId);
} else {
alert("inget alternativ valt! = " + accessId);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<!-- Start inputs -->
<input type="text" id="access_input" value="">
<br>
<div class="btn-group">
<button type="button" class="btn btn-default"><i id="accessIcon" class="fa "> </i> <span id="access">Action</span>
</button>
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><i class="fa fa-globe"></i> Alla
</li>
<li><i class="fa fa-group"></i> Vänner
</li>
<li><i class="fa fa-eye"></i> Privat
</li>
</ul>
</div>
Add to each links with class 'access' data attributes first for icon class name and second for title. Example for first link:
<a href="javascript:void(0);" class="access" id="0" data-icon="globe" data-title="Alla">
And your onclick can be simplified to:
$(".access").click(function(e) {
$("#access").html($(this).data('title'));
$("#accessIcon").removeClass();
$("#accessIcon").addClass('fa fa-' + $(this).data('icon'));
$('#access_input').val($(this).attr('id'));
});
Well, for starters, I would extract the UI details that are buried deep in your conditions, so that you may use variables instead:
var accessTypes = [
{ title: 'Alla', icon: 'fa-globe' },
{ title: 'Vänner', icon: 'fa-group' },
{ title: 'Privat', icon: 'fa-eye' }
];
Then you could simply do:
$(".access").click(function(e) {
var accessId = $(this).attr('id');
var access = accessTypes[accessId];
$("#access").html(' ' + access.title);
$("#accessIcon").attr('class', 'fa ' + access.icon);
$('#access_input').val(accessId);
});
Note that this works only because the id of your buttons are matching the array index in accessTypes. This solution will break down once you add a second set of buttons for something else.
I would suggest that you move away from relying on id to a data attribute for this purpose, and I would also use string identifiers, although doing just either one of them would be sufficient to solve the problem.
<a href="javascript:void(0);" class="access" data-id="all"> <!-- etc -->
You would then use:
var accessTypes = {
all: { title: 'Alla', icon: 'fa-globe' },
friends: { title: 'Vänner', icon: 'fa-group' },
'private': { title: 'Privat', icon: 'fa-eye' }
};
And...
$(".access").click(function(e) {
var accessId = $(this).data('id');
var access = accessTypes[accessId];
...
});

Categories

Resources