Jquery UI Accordion won't collapse when created dynamically with web database - jquery-ui-accordion

This accordion works fine when it's on the page by itself, but when I dynamically populate the individual title/content pairs via a web database, the title and content are uncollapsed. Is there a problem with the way I implemented it?
The rest of the database (inserting dictionary term and definition in 2 different fields) is functioning flawlessly without the accordion function. Understandablhy, I want to integrate the accordion so there's less scrolling for the user.
Here is the code implemented, then the code (commented out) straight from the source for comparison:
function showRecords() {
var results = '';
results.innerHTML = '';
db.transaction(function(tx) {
tx.executeSql(selectAllStatement, [], function(tx, result) {
dataset = result.rows;
for (var i = 0, item = null; i < dataset.length; i++) {
item = dataset.item(i);
results.innerHTML = '<div id="accordion">';
results.innerhtml += '<h3>' + item['term'] + '</h3><div><p>' + item['definition'] + '<button class="glossaryButton2" onClick="loadRecord('+i+')">Edit</button> <button class="glossaryButtonDel" style="float:right;" onClick="deleteRecord(' + item['id'] + ')">Delete</button></p><hr></div>';
}
});
});
results.innerHTML += '</div>';
// TRIED: $('#accordion').html(results).accordion({collapsible: true});
// TRIED: $("#accordion").accordion({collapsible: true});
// getter
var collapsible = $( "#accordion" ).accordion( "option", "collapsible" );
// setter
$( "#accordion" ).accordion( "option", "collapsible", true );
exportRecords();
}
(Explanation of $('#accordion').html(results).accordion({collapsible: true}); : "The accordion call only works on matching elements in the DOM at the point it is called. Since you are adding the accordion dynamically, there is nothing to match. You need to re-apply the accordion after loading the new content." I think this is the point at which I'm clueless. )
/* The HTML of original accordion:
<div id="accordion">
<h3>Section 1</h3>
<div>
<p>Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi.</p>
</div>
</div>
*/
This above problem is not unique to Jquery UI. I've had exactly the same problem with 4-5 other Javascript accordions - I keep trying! I always try the accordion by itself; if it works, then I integrate it with the database + innerHTML -- and find it quits collapsing.
(FYI: This code is sharing space with Zurb Foundation 3, and uses the Jquery that came with it. It works fine with the above HTML accordion version when used apart from the database, so that can't be the issue.)

Related

how to make particular part of string bold in React JS?

I am building reactJs app. I am using textArea from react-spectrum/ prime. In this textArea , I need to show some text in bold letters.
I have tried something like this.
const data = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.'
I need to make "popularised in" in bold letters.
i have tried implementing style in textarea, also tried with the following function
function boldString(str, find){
var re = new RegExp(find, 'g');
return str.replace(re, '<b>'+find+'</b>');
}
but this doesn't worked.
If anyone knows the solution please help.
Thanks.
try to use dangerouslySetInnerHTML as follows
function boldString(str, find){
var re = new RegExp(find, 'g');
return str.replace(re, '<b>'+find+'</b>');
}
var str = boldString('input string', 'find value')
<div dangerouslySetInnerHTML={{ __html: str}}></div>
By using "react-contenteditable" library https://www.npmjs.com/package/react-contenteditable we can edit the content and if we want to bold particular text, we can do it by using html tags.
import React from 'react'
import ContentEditable from 'react-contenteditable'
class MyComponent extends React.Component {
constructor() {
super()
this.contentEditable = React.createRef();
this.state = {html: "<b>Hello <i>World</i></b>"};
};
handleChange = evt => {
this.setState({html: evt.target.value});
};
render = () => {
return <ContentEditable
innerRef={this.contentEditable}
html={this.state.html} // innerHTML of the editable div
disabled={false} // use true to disable editing
onChange={this.handleChange} // handle innerHTML change
tagName='article' // Use a custom HTML tag (uses a div by default)
/>
};
};
Problem with solution in your question is that you are trying to insert DOM element trough string, and you can use that dangerouslySetInnerHTML prop but that is a bit hacky and ad hoc.
You can try this out. This will cover any value that you want to bold:
const data =
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
export default function App() {
const boldPartOfText = (boldingText, targetText) => {
if (!targetText) {
return "";
}
const indexOfText = targetText.indexOf(boldingText);
if (indexOfText === -1) {
return targetText;
}
const endIndexOfText = indexOfText + boldingText.length;
return (
<>
{`${targetText.slice(0, indexOfText)}`}
<b>{targetText.slice(indexOfText, endIndexOfText)}</b>
{targetText.slice(endIndexOfText)}
</>
);
};
return <div className="App">{boldPartOfText("Lorem ", data)}</div>;
}
I made codesandbox with working example: https://codesandbox.io/s/stack-overflow-bolding-text-zlucy

React equivilant of `$(window).scrollTop()`

I'm trying to check if a user has scrolled to the bottom of a document. There's a popular question answered only in Jquery.
How can the top answer be done in React?
So far, I figured out that the equivalent of:
$(window).height is: window.pageYOffset
$(document).height is: document.documentElement.offsetHeight
I'm missing $(window).scrollTop.
There is a new API in the window object. Example here is for scroll to top. You can make it for the bottom also. instead of top give as bottom
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo
Top:
window.scrollTo({
top: 100,
left: 100,
behavior: 'smooth'
});
Bottom:
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' })
Check the bottom of the page in javascript
window.onscroll = function() {
var d = document.documentElement;
var offset = d.scrollTop + window.innerHeight;
var height = d.offsetHeight;
console.log('offset = ' + offset);
console.log('height = ' + height);
if (offset >= height) {
console.log('At the bottom');
}
};
use with the combination of react hooks
Follow these articles and code references:
1. https://gist.github.com/romanonthego/223d2efe17b72098326c82718f283adb
2. https://medium.com/better-programming/create-a-scroll-to-top-arrow-using-react-hooks-18586890fedc
You are looking to check if a user has scrolled to the bottom of a document using React/JS.
Here you go.
Working demo in codesandbox
Code snippet
export default function App() {
const [isPageEnd, setIsPageEnd] = useState(false);
useEffect(() => {
document.addEventListener("scroll", trackScrolling);
return () => document.removeEventListener("scroll", trackScrolling);
}, []);
const trackScrolling = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
setIsPageEnd(true);
}
if (false) {
console.log(" bottom reached");
document.removeEventListener("scroll", trackScrolling);
}
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{isPageEnd ? (
<p> you reached bottom of page. Refresh page and begin again</p>
) : (
<p>
Lorem ipsum, or lipsum as it is sometimes known, is dummy text used in
laying out print, graphic or web designs. The passage is attributed to
an unknown typesetter in the 15th century who is thought to have
scrambled parts of Cicero's De Finibus Bonorum et Malorum for use in a
type specimen book Lorem ipsum, or lipsum as it is sometimes known, is
dummy text used in laying out print, graphic or web designs. The
passage is attributed to an unknown typesetter in the 15th century who
is thought to have scrambled parts of Cicero's De Finibus Bonorum et
Malorum for use in a type specimen book Lorem ipsum, or lipsum as it
is sometimes known, is dummy text used in laying out print, graphic or
web designs. The passage is attributed to an unknown typesetter in the
15th century who is thought to have scrambled parts of Cicero's De
Finibus Bonorum et Malorum for use in a type specimen book Lorem
ipsum, or lipsum as it is sometimes known, is dummy text used in
laying out print, graphic or web designs. The passage is attributed to
an unknown typesetter in the 15th century who is thought to have
scrambled parts of Cicero's De Finibus Bonorum et Malorum for use in a
type specimen book Lorem ipsum, or lipsum as it is sometimes known, is
dummy text used in laying out print, graphic or web designs. The
passage is attributed to an unknown typesetter in the 15th century who
is thought to have scrambled parts of Cicero's De Finibus Bonorum et
Malorum for use in a type specimen book
</p>
)}
</div>
);
}
You are expecting too much from React. React is only concerned with rendering data to the DOM. You can still use jQuery with React is you don't like using pure JS.
Example
const { useState, useEffect } = React;
const App = () => {
useEffect(() => {
$(window).scrollTop($(document).height());
}, [])
return <div style={{height: '200vh', background: 'blue'}}></div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<div id="root"></div>
This probably will work for you. You can use React SyntheticEvent for this purpose
class SomeComponent extends React.Component {
findBottomScroll = e => {
let element = e.target
if (element.scrollHeight - element.scrollTop === element.clientHeight) {
// whatever you want
}
}
render() {
return (
<div onScroll={this.handleScroll}></div>
)
}
}

Cannot create property 'type' on string - radio button filters

If I define radio button filters in Angular like so:
<input type="radio" ng-model="filter.type" value="rose" class="type-filter"> Rose<br>
<input type="radio" ng-model="filter.type" value="tomato" class="type-filter"> Tomato<br>
And the ng-repeat to show the data is:
<div ng-repeat="node in allnodesFiltered | filter:{ plantArray: filter.type}" class="row product-item">
{{node.title}}
The filtering works perfectly. BUT, if I try to use ng-repeat in the filter like this:
<div ng-repeat="plant in plantFilters">
<input type="radio" ng-model="filter.type" ng-value="filter" class="type-filter"> Grass
{{plant}}
</div>
I get the error:
TypeError: Cannot create property 'type' on string 'rose'
at fn.assign (eval at <anonymous>
Here is an example of an item in the json array:
title: "Euismod Lucidus Oppeto Probo",
body: "Abico adipiscing facilisi nunc singularis sudo. Antehabeo humo melior neo obruo ulciscor voco. Aliquam commoveo ea mauris nutus os saepius zelus. Brevitas dolus uxor. Ad cogo decet nobis nutus obruo olim turpis venio virtus. Damnum dignissim lobortis meus mos plaga. Eros iriure loquor macto natu paulatim vel. Consequat humo jus nulla. Abico conventio ibidem si tum typicus uxor volutpat. Diam nutus uxor ymo. Abluo caecus imputo loquor lucidus macto nibh obruo usitas.",
Path: "public://product-images/imagefield_THXgQg.jpg",
productType: "Compost, Weedkiller",
plant: "Rose, Tomato"
Error itself is saying that you are trying to create a property on a string.In your case ng-repeat will work as you want if array is a "array of JSON object" (not json text). When you prepare your array for ng-repeat, you are pushing json object into array not json text.
var jsonObject = JSON.parse(text);
I managed to figure this out. In the ng-model you can refer to the parent like this:
ng-model="$parent.filter.type"
I would love it if someone could exaplain how this works. But thanks for the input Akhilesh Jaiswal
This error occors also if you instantiate a variable as string not as object:
var myObject = " "; //this will launch the error
and
var myObject = {}; //this will work

Creating a wordcloud generator in Angularjs

I previously created a very simple Wordcloud generator which I would now like to port to work in an angularjs way following best practices.
This is what I did previously in the jquery project:
I had a variable containing a selectin of text:
var text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit........Suspendisse fermentum venenatis tincidunt.";
I then split the text variable into an array of words
var word_list = text.split(/\W+/);
Below is where I populate my cloud. I randomly allocate the size a word should be with Math.random which then corresponds to a css class which sets the font-size ( class="cloud_' + wordSize + '" )
function populateKeywordCloud(wordCount, selector) {
for (i = 0; i < wordCount ; i++) {
wordSize = Math.floor((Math.random() * 10) + 1);
$(selector + ' #keyword_cloud .dataBoxContent').append('<span class="cloud_' + wordSize + '" title="Keyword wordSize ' + wordSize + ' times" ">' + word_list[i] + '</span> ');
}
}
The cloud is initialised in the following way:
$(document).ready(function () {
populateKeywordCloud(30, '.summary_page');
}
So my question is how will I do this in the angularjs way?
Do I create a custom directive and create a link function where I do all my wordcloud logic. A template file called under templateUrl: is then to take the wordcloud data and populate the cloud using ng-repeat
Or do I create a directive that pulls in the keyword data from a wordcloud controller which is in charge of generating the data to be used by the directive?
In angular, you should forget about selectors. Instead, think controller elements. For instance, as your tag cloud is dynamic, it should be wrapped as a controller.
<div id="keyword_cloud" ng-controller="tagCloudCtrl">
<div class="dataBoxContent">
<span ng-repeat="word in words" class="cloud_{{ word.size }}" title="Keyword wordSize {{ word.size }} times">{{ word.text }}</span>
</div>
</div>
This is the template. Notice the ngRepeat directive that lets you iterate over an attribute of the $scope of tagCloudCtrl. Here, we directly use {{...}} to evaluate the word's size and text.
Code-size, we fill up this words scope variable:
angular.module('tagcloud-app', [])
.value('WORD_COUNT', 3)
.service('tagService', function() {
// Fetch your words here
return {
getTags: function() {
return ['aaaaa', 'bBbb', 'CCC', 'dd'];
}
};
})
.controller('tagCloudCtrl', ['$scope', 'tagService', 'WORD_COUNT',
function($scope, tagService, WORD_COUNT) {
var wordSize, word_list = tagService.getTags();
// This will make the "words" array visible from associated template
$scope.words = [];
for (var i = 0; i < WORD_COUNT; i += 1) {
$scope.words.push({
text: word_list[i],
size: Math.floor((Math.random() * 10) + 1)
});
}
}
]);
Moreover, don't forget to separate logic: as you can see, I made a separate service to fetch tags and to store your word count. This will make your app very dynamic, flexible and reusable.
Check out my working example on plnkr.
Note that, as mentionned risto, you can use directives to completely abstract your tag cloud from the rest of your app. Once you will be at ease with regular controllers, check out directives at AngularJS's
Enjoy your AngularJS journey!
I would say it's better to encapsulate as much of your logic as possible, so create a directive with all of your logic inside of it, if you can.
If you feel like it needs a controller, try to package it into a module with it's corresponding directive. Keep it reusable.

Angular.js text highlight by search keyword require a suggestion

I am trying to make a text highlight using a search keyword. I did my best. But I couldn't get a result of what I required.
Now I don't have any idea to proceed further to complete my requirement. any one give the correct suggestion or help me to complete the highlight by search key word functionality?
Actually my search input sits in the header of the page. ( global ) from I would like to highlight the text in the page by keyword entries.
here is my code :
var app = angular.module('plunker', []);
app.controller('headerController', function ($scope) {
var replacer = function(match, item) {
return '<span class="highlight">'+match+'</span>';
}
var tokenize = function(keywords) {
keywords = keywords.replace(new RegExp(',$','g'), '').split(',');
var i;
var l = keywords.length;
for (i=0;i<l;i++) {
keywords[i] = '\\W'+keywords[i].replace(new RegExp('^ | $','g'), '')+'\\W';
}
return keywords;
}
$scope.search = {value:''}
$scope.$watch('search.value', function(newval, oldval) {
if(!newval) {
return false;
}
var tokenized = tokenize(newval);
var regex = new RegExp(tokenized.join('|'), 'gmi');
console.log( tokenized );
})
})
app.controller('controller1', function($scope) {
$scope.para1 = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.';
});
app.controller('controller2', function($scope) {
$scope.para2 = 'It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.';
});
app.controller('controller3', function($scope) {
$scope.para3 = 'The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.';
});
Live Demo

Resources