Lodash map to array of objects - lodash

I'm starting from a jQuery wrapper with a number of <A>-tag elements in it. The result I want is:
[{href: "http://...", text: "The inner text"}, {...}, ...]
Thus far I got this:
_.map($pubs, ($pub) => _.pick($pub, 'href', 'innerText'))
That works, but it looks like there's a better way, and the inner text property is named "innerText" instead of "text". And I do want the innerText of the elements and not just the .text() as that doesn't clean up the output (newlines, whitespace,...).

You can use ES6 destructuring, and assign text to a new variable. Now you can create a new object with the href, and text variables using shorthand property names:
const links = $('a').toArray();
const result = links.map(({ href, innerText: text }) => ({ href, text }));
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Google
Facebook
Apple
You can also use jQuery's '.map()`:
const result = $('a').map((k, { href, innerText: text }) => ({ href, text })).toArray();
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Google
Facebook
Apple

Related

How to handle event on html render by computed function in vue js?

I'm using vue 2. I have a text get from api.
"Hello everyone! My name is [input]. I'm [input] year old".
Now, I have to replace the [input] with an html input and handle the onKeyUp for this input.
What I have to do?
I used computed render html, but it not work with v-on:xxx.
content.replaceAll('[answer]', '<input type="text" class="input_answer" v-on:click="handleInput()"/>')
Thanks!
After spending an hour and so on this requirement, I came up with the solution.
Here you go (I added all the descriptive comments/steps in the below code snippet itself) :
// Template coming from API
var textFromAPI = "<p>Hello everyone! My name is [input]. I'm [input] year old</p>";
// getting the array of input tags. So that we can loop and create the proper input element.
const matched = textFromAPI.match(/(input)/g);
// Iterating over an array of matched substrings and creating a HTML element along with the required attributes and events.
matched.forEach((el, index) => {
textFromAPI = textFromAPI.replace('[input]', `<input type="text" id="${index + 1}" v-model="inputValue[${index}]" v-on:keyup="getValue"/>`);
})
// Here, we are compiling the whole string so that it will behave in a Vue way.
var res = Vue.compile(textFromAPI)
var app = new Vue({
el: '#app',
data: {
compiled: null,
inputValue: []
},
render: res.render,
staticRenderFns: res.staticRenderFns,
mounted() {
setTimeout(() => {
this.compiled = res;
})
},
methods: {
getValue() {
// Here you will get the updated values of the inputs.
console.log(this.inputValue);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
</div>
Thanks # Rohit Jíndal, but!
When I use vue2 and it doesn't work. And there is an error:
TypeError: Cannot read properties of undefined (reading 'string')
I build this to a component and use anywhere in my project.
<render-html :text="question.quest_content" #handleAnswer="handleAnswer"></render-html>
I used and it's work.
this.$options.staticRenderFns = string.staticRenderFns;
return string.render.bind(this)(h)
Thanks so much!

How to make a div object when clicked to do something

I have 6 objects and here is an example of one of the objects:
<div class="item2"><div class="circle2"><img class="device2" src="Devices/mouse.png" alt="Mouse"></div></div>
and what I would like to do is when that object is clicked to pass a variable and activate a method in the backend and refresh the data on the page.
You can use fetch to retrieve data from the server (assuming you have a controller endpoint set up do do that). We would need a little more information as to where the variable is coming from and how you will use the data coming from the server trefine this answer.
<div class="item2" id="item2"><div class="circle2"><img class="device2" src="Devices/mouse.png" alt="Mouse"></div></div>
<script>
const i2 = document.getElementById('item2')
i2.addEventListener('click', function() {
let fetchUrl ="https://www.yourdomain.com/api?id=" + yourvariable;
fetch(fetchUrl)
.then(response => response.json())
.then(data => {
//do something with data
})
})
</script>

Unable to use Lazy load + Dynamic image manipulation Cloudinary

I am unable to use the feature Cloudinary Lazyload + Dynamic image manipulation both at the same time.
Is there any trick to use both the function at the same time?
I am using an HTML website.
My code is
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/cloudinary-core#latest/cloudinary-core-shrinkwrap.js"></script>
<script type="text/javascript">
var cl = cloudinary.Cloudinary.new({cloud_name: "syg"});
// replace 'demo' with your cloud name in the line above
cl.responsive();
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const imageObserver = new IntersectionObserver((entries, imgObserver) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const lazyImage = entry.target
console.log("lazy loading ", lazyImage)
lazyImage.src = lazyImage.dataset.src
}
})
});
const arr = document.querySelectorAll('img.lzy_img')
arr.forEach((v) => {
imageObserver.observe(v);
})
})
</script>
<img class="cld-responsive lzy_img" data-src="https://res.cloudinary.com/syg/image/upload/w_auto,c_scale/sample.jpg" />
The responsive script will apply the relevant width value and replace w_auto in the URL based on the container size.
Since your code does not limit the <img> container, it applies the max width size of the screen.
For testing purposes, you can wrap your <img> element with <div style="width:50%;"></div> and you will see that the image URL adjusts the width transformation accordingly:
<div style="width:50%;">
<img class="cld-responsive lzy_img" data-src="https://res.cloudinary.com/syg/image/upload/w_auto,c_scale/v346346/sample.jpg"/>
</div>
In addition, you can take a look at the following broader implementation of LQIP+Lazy Loading+Responsive with Cloudinary for reference and ideas on how to implement these features within your site's pages.

In Cypress how to found count a selection with same ID and get the length?

I have a such HTML code.
<div id ='pages'>
<div id='wrapper'>1 </div>
<div id='wrapper'>2 </div>
</div>
I am want to find elements count with id wrapper.
I using Cypress. I'm starting to learn Cypress.
If I try:
cy.get('div#wrapper').should('have.length', 2)
I get AssertionError:
CypressError: Timed out retrying: expected 1 to equal 2
As jonrsharpe pointed out, it's invalid HTML to have multiple elements with identical id attribute.
That being said, DOM is quite smart and can recover and work even with invalid HTML. Duplicate-id elements shouldn't cause much trouble.
If you e.g. try doing document.querySelectorAll('#wrapper') it should return list of 2 elements (in your case).
Problem is, Cypress is using jQuery to query the DOM instead of using native DOM methods and I guess jQuery isn't as smart (or it's more pedantic).
That being said, I can't reproduce that error when running:
// succeeds
cy.get('div#wrapper').should('have.length', 2)
Only when querying #wrapper directly (without the preceding div):
// fails
cy.get('#wrapper').should('have.length', 2)
I reckon this is because jQuery uses a heuristic of exiting early when a selector string (#wrapper) contains only a single id (and that's why div#wrapper returns both elements).
Also, your solution in comments (cy.get('#pages') .find('div#wrapper') .should(($div) => { expect($div).to.have.length(2) })), while working, isn't ideal because it won't retry. Let me demonstrate:
In the following code, the 2nd #wrapper will appear in the DOM only after 1 sec.
describe( 'test', () => {
beforeEach(() => {
cy.document().then( doc => {
doc.body.innerHTML = `
<div id='pages'>
<div id='wrapper'>1</div>
</div>
`;
setTimeout(() => {
doc.body.innerHTML = `
<div id='pages'>
<div id='wrapper'>1</div>
<div id='wrapper'>2</div>
</div>
`;
}, 1000 );
});
});
// will fail
it('solution A', () => {
cy.get('#pages') // <- won't be retried
.find('div#wrapper') // <- only this command will be retried
.should( $div => expect($div).to.have.length(2) );
});
// will pass
it('solution B', () => {
cy.get('#pages #wrapper') // <- will be retried and succeed in 1sec
.should( $div => {
expect($div).to.have.length(2);
});
});
// will pass
it('solution C', () => {
cy.get('#pages')
.should($pages => {
// using native DOM querying
expect($pages[0].querySelectorAll('#wrapper').length).to.eq(2);
});
});
});
Thus, you should go with solution similar to B or C.

How to embed codepen as HTML in vue.js

I can't figure out how to embed a codepen using the recommended HTML method i a Vue application.
As <script> tag cannot be part of a Vue component template, I tried to add it to index.html where my Vue application is injected without luck. However, when I tried to paste the html code outside the div where Vue resides, the code got turned into an iFrame as it should.
Here is the HTML embed:
<p data-height="265" data-theme-id="0" data-slug-hash="JyxKMg" data-default-tab="js,result" data-user="sindael" data-embed-version="2" data-pen-title="Fullscreen image gallery using Wallop, Greensock and Flexbox" class="codepen">See the Pen Fullscreen image gallery using Wallop, Greensock and Flexbox by Dan (#sindael) on CodePen.</p>
And the script:
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
Embedding an iFrame directly works fine, but I wonder. Is there a way how to get the html working?
Look into the https://static.codepen.io/assets/embed/ei.js, then you will see it executes two steps:
check document.getElementsByClassName if exists, create it if not.
one IIFE to execute the embed.
So one hacky way as below simple demo:
copy the source codes from https://static.codepen.io/assets/embed/ei.js
copy the codes of first step then wrap it as one function = _codepen_selector_contructor
copy the codes of second step and remove () from the end, then wrap it as one function = _codepen_embed_method
create one vue-directive (I prefer using the directive to support the features which directly process Dom elements, you can use other solutions), then execute _codepen_selector_contructor and _codepen_embed_method
Probably you want to replace document inside _codepen_embed_method with el instead, then execute _codepen_embed_method(el). so that it will not affects other elements.
Below demo uses the hook='inserted', you could use other hooks if inserted can't meet your requirements.
let vCodePen = {}
vCodePen.install = function install (Vue) {//copy from https://static.codepen.io/assets/embed/ei.js
let _codepen_selector_contructor = function () {
document.getElementsByClassName||(document.getElementsByClassName=function(e){var n,t,r,a=document,o=[];if(a.querySelectorAll)return a.querySelectorAll("."+e);if(a.evaluate)for(t=".//*[contains(concat(' ', #class, ' '), ' "+e+" ')]",n=a.evaluate(t,a,null,0,null);r=n.iterateNext();)o.push(r);else for(n=a.getElementsByTagName("*"),t=new RegExp("(^|\\s)"+e+"(\\s|$)"),r=0;r<n.length;r++)t.test(n[r].className)&&o.push(n[r]);return o})
}
let _codepen_embed_method = //copy from https://static.codepen.io/assets/embed/ei.js then removed `()` from the end
function(){function e(){function e(){for(var e=document.getElementsByClassName("codepen"),t=e.length-1;t>-1;t--){var u=a(e[t]);if(0!==Object.keys(u).length&&(u=o(u),u.user=n(u,e[t]),r(u))){var c=i(u),l=s(u,c);f(e[t],l)}}m()}function n(e,n){if("string"==typeof e.user)return e.user;for(var t=0,r=n.children.length;t<r;t++){var a=n.children[t],o=a.href||"",i=o.match(/codepen\.(io|dev)\/(\w+)\/pen\//i);if(i)return i[2]}return"anon"}function r(e){return e["slug-hash"]}function a(e){for(var n={},t=e.attributes,r=0,a=t.length;r<a;r++){var o=t[r].name;0===o.indexOf("data-")&&(n[o.replace("data-","")]=t[r].value)}return n}function o(e){return e.href&&(e["slug-hash"]=e.href),e.type&&(e["default-tab"]=e.type),e.safe&&("true"===e.safe?e.animations="run":e.animations="stop-after-5"),e}function i(e){var n=u(e),t=e.user?e.user:"anon",r="?"+l(e),a=e.preview&&"true"===e.preview?"embed/preview":"embed",o=[n,t,a,e["slug-hash"]+r].join("/");return o.replace(/\/\//g,"//")}function u(e){return e.host?c(e.host):"file:"===document.location.protocol?"https://codepen.io":"//codepen.io"}function c(e){return e.match(/^\/\//)||!e.match(/https?:/)?document.location.protocol+"//"+e:e}function l(e){var n="";for(var t in e)""!==n&&(n+="&"),n+=t+"="+encodeURIComponent(e[t]);return n}function s(e,n){var r;e["pen-title"]?r=e["pen-title"]:(r="CodePen Embed "+t,t++);var a={id:"cp_embed_"+e["slug-hash"].replace("/","_"),src:n,scrolling:"no",frameborder:"0",height:d(e),allowTransparency:"true",allowfullscreen:"true",allowpaymentrequest:"true",name:"CodePen Embed",title:r,"class":"cp_embed_iframe "+(e["class"]?e["class"]:""),style:"width: "+p+"; overflow: hidden;"},o="<iframe ";for(var i in a)o+=i+'="'+a[i]+'" ';return o+="></iframe>"}function d(e){return e.height?e.height:300}function f(e,n){if(e.parentNode){var t=document.createElement("div");t.className="cp_embed_wrapper",t.innerHTML=n,e.parentNode.replaceChild(t,e)}else e.innerHTML=n}function m(){"function"==typeof __CodePenIFrameAddedToPage&&__CodePenIFrameAddedToPage()}var p="100%";e()}function n(e){/in/.test(document.readyState)?setTimeout("window.__cp_domReady("+e+")",9):e()}var t=1;window.__cp_domReady=n,window.__CPEmbed=e,n(function(){new __CPEmbed})}
let defaultProps = {class: 'codepen', 'data-height':265, 'data-theme-id':0, 'data-slug-hash':'', 'data-default-tab':'js,result', 'data-user':'sindael', 'data-embed-version':'2', 'data-pen-title':''}
Vue.directive('code-pen', {
inserted: function (el, binding, vnode) {
let options = Object.assign({}, defaultProps, binding.value)
Object.entries(options).forEach((item) => {
el.setAttribute(item[0], item[1])
})
setTimeout(() => {
_codepen_selector_contructor()
_codepen_embed_method() //_codepen_embed_method(el); you can pass el to take place of `document`
}, 100)
},
componentUpdated: function (el, binding, vnode) {
}
})
}
Vue.use(vCodePen)
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
keyword: '',
},
mounted: function () {
},
methods: {
}
})
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<p v-code-pen="{class: 'codepen', 'data-height':'265', 'data-theme-id':0, 'data-slug-hash':'JyxKMg', 'data-default-tab':'js,result', 'data-user':'sindael', 'data-embed-version':'2', 'data-pen-title':'Test'}">
</p>
</div>