Two data bind attributes are not working in KnockoutJS - javascript

I am using a function which is returning an integer value based on that I am looping it to generate html divs. Please see the below code:
<div data-bind="foreach: new Array(getCartTotalParam())">
<div data-bind='text : $index()+1, css: { active: getCartParam("summary_count") >= $index()+1 }'></div>
</div>
the getCartTotalParam() is returning an integer let say 21, so I am generating 21 divs inside it.
Now I want to add a css class (as active).
The logic is I have used css binding which is call getCartParam("summary_count"). It checks the returned value and the loop's iteration index and based on this comparison I want to add css class.
But my code is not working. I have referred the doc but can't figure out what was missing.

I don't see anything wrong with your code given above. There might be a mistake in your logic.
The css binding with the above-given (question) syntax would apply active css if the given expression getCartParam("summary_count") >= $index()+1 is true otherwise it will not apply anything.
Here is working jsbin

You should change your $index()+1 as ($index()+1) in your <div> tag like this,
<div data-bind='text : $index()+1, css: { active: getCartParam("summary_count") >= ($index()+1) }'></div>
Here is a working DEMO for you: http://jsfiddle.net/GSvnh/5689/
Hope this helps!

Related

Can't get my elements from DOM to add them CSS properties?

I am working on a shopify template, so I a tryig to edit some code, and change some CSS properties using JS.
When I inspect my elements, I see that :
I am intersted in four elements, with classes "spr-container", "spr-summary-caption", "spr-summary-actions", "spr-content", So i wrote this code :
<script>
let urlPr = window.location.href;
if(urlPr.includes("products")){
setTimeout(function(){
console.log(document.getElementsByClassName("spr-container"));
console.log(document.getElementsByClassName("spr-summary-caption"));
console.log(document.getElementsByClassName("spr-summary-actions"));
console.log(document.getElementsByClassName("spr-content"));
},1000);
}
</script>
And I get this on my console :
Which means I am getting emty collections, but when I click one of them, the collection length becomes 1 and when I click the element shown in the inspector it takes me to my wanted element.
This is causing me problem, because when I try to get my element like that :
console.log(document.getElementsByClassName("spr-container")[0]);
I get :
undefined
Is there anyway that can help me solve this problem.
Any help would be much appreciated.
Wrap it:
document.addEventListener("DOMContentLoaded", getData);
function getData() {
let urlPr = window.location.href;
if(urlPr.includes("products")) {
console.log(document.getElementsByClassName("spr-container"));
console.log(document.getElementsByClassName("spr-summary-caption"));
console.log(document.getElementsByClassName("spr-summary-actions"));
console.log(document.getElementsByClassName("spr-content"));
}
}

Remove any specific html code using javascript

In the past I used Google Developer Console to delete some specific divs on a page. I could do it manually of course but in some cases where the divs where many I had to use the console. I had a single line code that did the job (I found it while searching the internet) but I lost my note.
So how can I delete using javascript any html code (by copy pasting the code).
Something like:
elements = $('<div ... </div>');
elements.remove();
OR
$('<div ... </div>').remove();
Any ideas? I am not an expert in javascript (obviously) and I've been searching stackoverflow for hours without finding anything that works.
UPDATE: I think some people might get confused with my question. Google developer console accepts javascript command lines. So even though I ask for javascript I will use the code on the google developer console.
UPDATE 2 :
Here is an example of a div I need to delete. Keep in mind I want to copy paste the entire code in the javascript code. Not just identify the div.
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
It's the data-entry-status="declined" that makes that div unique so I can't just identify the div using an id selector or a class selector. I need to put the entrire thing there and remove it.
I tried:
$('<div class="entry-status-overlay" data-entry-status="declined"><div class="entry-status-overlay__inner"><span class="entry-status-overlay__title">Declined</span></div></div>').remove();
It didn't remove the div.
Try to search the dom by its outerHTML.
function deleteDomByHtml(html){
html=html.replace(/\s/g,'');
$("*").each(function(){
if(this.outerHTML.replace(/\s/g,'')===html){
$(this).remove();
}
});
}
And try this line on this page:
deleteDomByHtml(`<span class="-img _glyph">Stack Overflow</span>`);
You cannot do by simply pasting the code. That will remove all the div element.
You may need a specific selector like id,class or child to specific parent to remove the element from the dom.
Consider this case the divs have common class but the data-entry-status is different. So you can get the dom using a selector and then check the dataset property.
For demo I have put it inside setTimeout to show the difference. In application you can avoid it
setTimeout(function() {
document.querySelectorAll('.entry-status-overlay').forEach(function(item) {
let getStatus = item.dataset.entryStatus;
if (getStatus === 'declined') {
item.remove()
}
})
}, 2000)
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div class="entry-status-overlay" data-entry-status="accepted">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">accepted</span>
</div>
</div>
Just add any attribute with [] and it will remove the element.
$('[class="entry-status-overlay"]').remove();
/*OR*/
$('[data-entry-status="declined"]').remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
function del(){
var h = document.body.outerHTML;
h = h.match('<div>...</div>');
h.length--;
return h;
}
I guess this will work just give it a try... i tried on browser console and it worked, this way you can match the exact you want.
I might as well add my take on this. Try running this in your console and see the question vanish.
// convert the whole page into string
let thePage = document.body.innerHTML,
string = [].map.call( thePage, function(node){
return node.textContent || node.innerText || "";
}).join("");
// I get some string. in this scenario the Question or you can set one yourself
let replacableCode = document.getElementsByClassName('post-layout')[0].innerHTML,
string2 = [].map.call( replacableCode, function(node){
return node.textContent || node.innerText || "";
}).join("");
// replace whole page with the removed innerHTML string with blank
document.body.innerHTML = thePage.replace(replacableCode,'');
If you want to identify divs with that particular data attribute, you can use a data-attribute selector. In the example below, I've used a button and click event to make the demo more visual, but in the console the only line you'd need would be:
$('div[data-entry-status="declined"]').remove();
$(function() {
$("#testbutton").click(function() {
$('div[data-entry-status="declined"]').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div id="x">Some other div</div>
<button type="button" id="testbutton">Click me to test removing the div</button>
See https://api.jquery.com/category/selectors/attribute-selectors/ for documentation of attribute selectors.
P.S. Your idea to paste some raw HTML into the jQuery constructor and then execute "remove" on it cannot work - you're telling jQuery to create an object based on a HTML string, which is, as far as it's concerned, a new set of HTML. It does not try to match that to something existing on the page, even if that exact HTML is in the DOM somewhere, it pays it no attention. It treats what you just gave it as being totally independent. So then when you run .remove() on that new HTML...that HTML was never added to the page, so it cannot be removed. Therefore .remove() has no effect in that situation.

jQuery selector for varying HTML structure

I'm working with a page which displays a product's price. Normally it looks like this:
<span id="priceText">
$26.94
</span>
When the item is on sale, it looks like this:
<span id="priceText">
<strike>$26.94</strike>
<span class="salePrice">$25.00</span>
</span>
I have a generic function which extracts the price from any page like so:
var getPrice = function(price_id) {
return jQuery(price_id).text();
};
Where price_id is the id of the element which contains the price.
As is plainly obvious, this will not work with the above structure since the "sale" version will return both $26.94 and $25.00 if I set price_id to priceText
I do not have control over the html on the product's page, so I can't change the structure. I need to use the getPrice function on other pages which do not have this HTML structure, so I also want to avoid changing it.
What I am looking for is some sort of jQuery selector which will return $25.00 if the item is on sale, or $26.94 if it isn't. Something like "return all text inside of priceText NOT in a strike tag"
I currently have a custom snippet which does the following:
jQuery('#priceText .salePrice').length ? jQuery('#priceText .salePrice').text() : jQuery('#priceText strike').text()
However I want to avoid custom lines of code like this. I think this may not be possible using only jQuery selectors but I'm hoping someone proves me wrong!
You can use a multiple selector.
jQuery('#priceText .salePrice, #priceText:not(:has(.salePrice))').text()
DEMO
Maybe you could reduce your condition by this:
($('#priceText .salePrice') || $('#priceText strike')).text()

Toggling between two divs using Polymer

I ran into a issue where using polymer I would like to toggle through two divs, the problem I have is, I want to use the polymer standard of toggling where they use: hidden?="{{toggleMe}}" as a attribute on the div and just bind it then make a function that would do the toggling or the show/hide that will look like this:
<div hidden?="{{divOne}}">TEST</div>
<div hidden?="{{divTwo}}">TEST2</div>
<a on-tap="{{change}}">Toggle</a>
<script>
Polymer('componentName',{
change: function(){
this.divOne = !this.divOne;
this.divTwo = !this.divTwo;
}
})
</script>
This above will show both and hide both together, I want the one displayed and the other hidden, So essentially switching between the two while starting with the one hidden and the other active, and then swapping states from there.
I tried this also with no luck as I can't do this or use the '!' on the left hand side:
!this.divOne = this.divOne;
this.divTwo = !this.divTwo;
Thanks for reading
this.divOne = !(this.divTwo = this.divOne);
I have found a fix to the question, i assigned true and false values to the bind hidden values before I used them (this assigns a true for hidden state and false for the separate values), Then when clicking on the toggle bind I just used the code of #Zikes to have the toggle work(thanks for that).
current working code
<div hidden?="{{divOne}}">TEST</div>
<div hidden?="{{divTwo}}">TEST2</div>
<a on-tap="{{change}}">Toggle</a>
<script>
Polymer('componentName',{
divOne: false,
divTwo:true,
change: function(){
this.divOne = !(this.divTwo = this.divOne);
}
})
</script>
Hope this can help clear someone in the future

How to select children and self with jQuery?

I'm wondering what the best way is to find children of an element in jQuery, but also include the parent in the 'find'.
Here's my simplified basic HTML setup:
<div id="container">
<form id="form1"> <!-- form 1 content --> </form>
<form id="form2"> <!-- form 2 content --> </form>
</div>
And I want a function like this...
function getForms ($container)
{
// Option 1
var $allForms = $container.find('form').andSelf().filter('form');
// Option 2
var $allForms = $container.find('form');
if ($container.is('form')) $allForms.add($container);
// Should return all the forms in the container if passed $('#container')
// Or return just one form if passed $('#form1')
return $allForms;
}
I'm fairly certain that both option 1 or 2 will work. Does anyone know which option above is more efficient? Are there other options which are more elegant or more efficient?
EDIT:
I wasn't happy with the .is() in option 2 because it didn't work when the container had multiple jQuery objects in it. So I came up with something like this:
// Option 3
function getContainerElements ($container, selector) {
return $container.find(selector).add($container.filter(selector));
}
I haven't tested it too much, but I think it'll work for all general cases.
Option 2 is better according to JSPerf tests (Tested in Chrome on linux)
You can see the results here and the tests if you want to try it in different browsers:
http://jsperf.com/children-and-self
Note: I've updated this test to use divs instead of forms (because forms inside other forms don't work: Form inside a form, is that alright?) and we want to test the case where the parent should be added to get the real performance impact as per comment below
EDIT
Added third option performance as requested in comment
If you are really only looking for a single element rather than a set of elements, then the following should work at least as well as your option 3 and be faster:
function getContainerElements ($container, selector) {
var filtered = $container.filter(selector);
return filtered.length ? filtered : $container.find(selector);
}
In case there are both descendant and root elements matching selector, this will return only the matching root elements, unlike your option 3, which will put everything together. If you do want that, then modern jQuery allows a simpler solution:
function getContainerElements ($container, selector) {
return $container.find(selector).addBack(selector);
}

Categories