angular split().join() not working for new line - javascript

let samplestring ="a:b;c:d;e:f"
this.detail = samplestring.split(";").join("\n");
<div fxLayout="row">
<span class="default_label_font">{{detail}}</span>
</div>
but not adding new line and giving response like
response sample i'm getting
I've tried using "" too but instead of adding break it concatenate it
I refer Split string with commas to new line

Another way to do it, I think much simpler, is to use [innerHtml] (docs) instead of interpolation and break lines with <br>.
Like this:
<div fxLayout="row">
<span class="default_label_font" [innerHtml]="detail"></span>
</div>
let samplestring = "a:b;c:d;e:f";
this.detail = samplestring.split(";").join("<br>");
StackBlitz for you to test and play.

If you need to print the text on separate lines you will have to add <br> inbetween. \n is not rendered by HTML, unless you use <pre>.
extract from component.ts
this.lines = samplestring.split(";");
extract from component.html
<ng-container *ngFor="let line of lines; i = index">
<br *ngIf="i != 0">{{line}}
</ng-container>

Issue is the element you are using to set. Span is a inline component. So line breaks will not work. You will have to use a block level element like Div
let samplestring = "a:b;c:d;e:f"
const detail = samplestring.split(";").join("\n");
document.querySelector('.default_label_font').innerText = detail;
<div fxLayout="row">
<div class="default_label_font"></div>
</div>

HTML
<h1 id="ovde">
...
</h1>
ts
let customItems = "1,2,3";
customItems = customItems.split(',');
for ( let i = 0; i < customItems.length; i++ )
customItems[i] = "- " + customItems[i] + "\n";
customItems = customItems.join('');
document.getElementById("ovde").innerHTML = customItems;

Related

How do I use For Loop in JavaScript to show the list?

I am a beginner in JavaScript and I can't figure out the following problem: I am trying to create a simple JavaScript Movie List. I have 10 lists on the Movie List. I tried to show all of the lists with for loop, but it doesn't work.
Here's the code:
function renderModal() {
for (let i = 0; i < listMovies.length; i++) {
let movieData = listMovies[i];
document.getElementById("poster").src = movieData.img;
document.getElementById("title").innerHTML = movieData.name;
document.getElementById("genre").innerHTML = movieData.genre;
document.getElementById("rating-num").innerHTML = "Rating: "+ movieData.rating + "/10";
document.getElementById("movie-desc").innerHTML = movieData.desc;
document.getElementById("imdb-page").href = movieData.link;
return movieData;
}
}
What do I have to do?
Help me to fix it!.
You can use template tag for list and render it into target element.I am showing an example.
Movie list
<div id="movieList"></div>
template for list
<template id="movieListTemplate">
<div class="movie">
<img src="" class="poster" alt="">
<div class="title"></div>
<div class="genre"></div>
<div class="rating-num"></div>
<div class="movie-desc"></div>
<div class="imdb-page"></div>
</div>
</template>
Javascript code:
if (listMovies.length > 0) {
const movileListTemplate = document.getElementById('movieListTemplate')
const movieRenederElement = document.getElementById('movieList')
for(const movie of listMovies) {
const movieEl = document.importNode(movileListTemplate.content, true)
movieEl.querySelector('.poster').src = movie.img
movieEl.querySelector('.title').textContent = movie.name
//use all queryselector like above
}
}
Your return movieData; will stop the loop dead. Not that running it more than once will change anything since you change the same elements over and over. IDs must be unique.
Here is a useful way to render an array
document.getElementById("container").innerHTML = listMovies.map(movieData => `<img src="${movieData.img}" />
<h3>${movieData.name}</h3>
<p>${movieData.genre}</p>
<p>Rating: ${movieData.rating}/10</p>
<p>${movieData.desc}
IMDB
</p>`).join("<hr/>");
With return movieData, the for loop will ends in advance.You should put it outside the for loop.

How to filter a list using an array of keywords?

Basically, I want to filter a list so it only shows items containing BOTH keywords inside the array.
Ex.:
searchArray = ['sys', 'config']
If the user type 'sys config', should only show "System configuration" and hide other items.
So far I came up with this, but it's not working properly, cause it shows items that contains one of the words and not both.
var searchArray = search.split(" ");
for(x in searchArray){
filteredMenu = $('.texto:contains(\'' + searchArray[x] + '\')')
}
Check that .every one of the keywords is included:
const texts = [...$('.texto')]
.filter(element => searchArray.every(
substr => element.textContent.includes(substr)
));
Demo:
searchArray = ['sys', 'config']
const texts = [...$('.texto')]
.filter(element => searchArray.every(
substr => element.textContent.includes(substr)
));
for (const text of texts) {
console.log(text);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="texto">
foo
</div>
<div class="texto">
config
</div>
<div class="texto">
sys config
</div>
<div class="texto">
system configuration
</div>
<div class="texto">
sys
</div>
<div class="texto">
bar
</div>
Also, in some cases it is useful to construct a regular expression ("regex") string, and to use this to perform the search.
I used the solution posted by a guy in Brazillian SO. Adding multiple :contains seems to work perfectly. Also, the answer from CertainPerformance works great!
var arrayBusca = ["config", "empresa"];
var stringBusca = '';
arrayBusca.forEach((item) => stringBusca = stringBusca.concat(`:contains("${item}")`));
console.log(stringBusca); // output: :contains("config"):contains("empresa")

Creating a template out of HTML Elements

lets say i have a parent-div. And in this div-container, i want to display 5 elements which have all the same structure. For example:
<div class="element">
<p class="name">
</p>
<div class="logo">
</div>
</div>
Is there a way to make an object or prototype out of it, so i dont have to generate every single HTML Element with their classes and src values with the appendChild-function and Dot-Notations in a for-loop?
Im thinking of something like:
for(let i = 0; i<=5;i++){
var element = new element(class,src1,src2 ...);
}
And the "element" is defined in a external class file or something familiar.
Im a beginner, so please show mercy :)
You'll need to clone the node from the template's content. For example:
const templateElement = document.querySelector("#someTemplate")
.content
.querySelector(".element");
// create an Array of nodes (so in memory)
const fiveNodes = [];
for (let i = 0; i < 5; i += 1) {
const nwNode = templateElement.cloneNode(true);
// ^ clone the whole tree
nwNode.querySelector("p.name").textContent += ` #${i + 1}`;
fiveNodes.push(nwNode);
}
// append the nodes to document.body
// this is faster than appending every element in the loop
fiveNodes.forEach(el => document.body.append(el));
<template id="someTemplate">
<div class="element">
<p class="name">I am node</p>
<div class="logo"></div>
</div>
</template>

Change text in div class with text from another

I'm trying to change the text in the div class "instock" with the words 'Made by' plus the "companyName" text
<div class="productDetails">
<div class="description">
<span class="companyName>The Company Name</span>
</div>
<div class="instock">Handmade to order</div>
<div>
I want instock to look like this:
<div class="instock">Made by The Company Name</div>
I've tried this
var companyName = document.getElementsByClassName('companyName');
var companyNameText = companyName.nodeValue;
var instock = document.getElementsByClassName('instock');
var instockAlt = instock.nodeValue;
instockAlt.textContent = 'Made by' + companyNameText;
Also as this might not always need to be done (when there is no company name for changing) I think I need to check if the span class is there first.
With JQuery, you can do the following
var companyName = $('.companyName').text();
if(companyName){
$('.instock').html('Made by ' + companyName);
}
With jQuery you could do:
$('.instock').html(function() {
if ( $(this).prev('.description').find('span').length ) return 'Made by ' + $(this).prev('.description').find('span').html()
})
jsFiddle example
You have a " missing in the <span>. The line:
var companyName = document.getElementsByClassName('companyName');
Returns a HTMLCollection. Either change it to:
var companyName = document.getElementsByClassName('companyName')[0];
var companyName = document.querySelector('.companyName');
If you are using jQuery, please use:
var companyName = $('.companyName');
var companyNameText = companyName.text();
var instock = $('.instock');
var instockAlt = instock.text();
instockAlt.text('Made by' + companyNameText);
The reason is, textContent is not available everywhere, while some browsers use innerText. jQuery takes care of browser incompatibilities like this.
Also, the final code is </div> not <div>.
If the whole code is a section block, then you need to use a contextual way:
$(function () {
$('.instock').each(function() {
if ( $(this).prev('.description').find('span').length )
$(this).text('Made by ' + $(this).prev('.description').find('span').text());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="productDetails">
<div class="description">
<span class="companyName">The Company Name</span>
</div>
<div class="instock">Handmade to order</div>
</div>

AngularJS is rendering <br> as text not as a newline

I am sure this has been asked before but I cannot find the answer.
I have an AngularJS script that is pulling from a DB and then rendering to content. Everything is working correctly except a couple of places that I am trying to concatenate some words with new lines between them.
**in the script.js**
groupedList[aIndex].CATEGORY = existingCategory+'\n'+thisCategory;
groupedList[aIndex].CATEGORY = existingCategory+'<br>'+thisCategory;
If I use the first line of the above code I don't see anything but there is not a new line in the redered html. If I use the second line the <br> get rendered as text and the output looks like this:
Instinct<br>Media
instead of
Instinct
Media
I can post the full script if that would be helpful but I am guessing there is something simple that I am just not seeing.
UPDATE
Here is the full js
function qCtrl($scope, $filter, $http, $timeout){
$scope.getCategories = function(){$http.post('quote.cfc?method=getCategories').success(function(data) { $scope.categories = data; }); }
$scope.getClassifications = function(){$http.post('quote.cfc?method=getClassifications').success(function(data) { $scope.classifications = data; }); }
$scope.getIndustries = function(){$http.post('quote.cfc?method=getIndustries').success(function(data) { $scope.industries = data; }); }
$scope.getKeywords = function(){$http.post('quote.cfc?method=getKeywords').success(function(data) { $scope.keywords = data; }); }
$scope.getSources = function(){$http.post('quote.cfc?method=getSources').success(function(data) { $scope.sources = data; }); }
$scope.getAllQuotes = function(){$http.post('quote.cfc?method=getAllQuotesJoined').success(function(data) { $scope.allQuotes = data; }); }
$scope.initScopes = function (){
$scope.getCategories();
$scope.getClassifications();
$scope.getIndustries();
$scope.getKeywords();
$scope.getSources();
$scope.getAllQuotes();
}
$scope.initScopes();
// SEARCH QUOTES
$scope.filteredQuotes = $scope.allQuotes;
$scope.search = {searchField:''};
$scope.searchQuote = function(){
var filter = $filter('filter');
var searchCrit = $scope.search;
var newlist = $scope.allQuotes;
var groupedList = [];
var idList = [];
newlist = filter(newlist,{TESTQUOTE:searchCrit.searchField});
for(i=0;i<10;i++){
aIndex = idList.contains(newlist[i].TESTIMONIALID);
if(aIndex >= 0){
thisKeyword = newlist[i].KEYWORD;
thisClassification = newlist[i].CLASSIFICATION;
thisCategory = newlist[i].CATEGORY;
existingKeyword = groupedList[aIndex].KEYWORD;
existingClassification = groupedList[aIndex].CLASSIFICATION;
existingCategory = groupedList[aIndex].CATEGORY;
if(thisKeyword != '' && existingKeyword.indexOf(thisKeyword) == -1){
groupedList[aIndex].KEYWORD = existingKeyword+' - '+thisKeyword;
}
if(thisClassification != '' && existingClassification.indexOf(thisClassification) == -1){
groupedList[aIndex].CLASSIFICATION = existingClassification+' \n '+thisClassification;
}
if(thisCategory != '' && existingCategory.indexOf(thisCategory) == -1){
groupedList[aIndex].CATEGORY = existingCategory+'<br>'+thisCategory;
}
} else {
idList.push(newlist[i].TESTIMONIALID);
groupedList.push(newlist[i]);
}
}
$scope.filteredQuotes = groupedList;
}
}
Array.prototype.contains = function ( needle ) {
for (j in this) {
if (this[j] == needle) return j;
}
return -1;
}
Here is the HTML
<div ng-repeat="q in filteredQuotes" class="well clearfix">
<h3>{{q.TITLE}}</h3>
<div class="row-fluid" style="margin-bottom:5px;">
<div class="span3 well-small whBG"><h4>Classification</h4>{{q.CLASSIFICATION}}</div>
<div class="span3 well-small whBG pipeHolder"><h4>Categories</h4>{{q.CATEGORY}}</div>
<div class="span3 well-small whBG"><h4>Key Words</h4>{{q.KEYWORD}}</div>
<div class="span3 well-small whBG"><h4>Additional</h4>Industry = {{q.INDUSTRY}}<br>Source = {{q.SOURCE}}</div>
</div>
<div class="well whBG">{{q.TESTQUOTE}}</div>
<div class="tiny">
Source comment : {{q.SOURCECOMMENT}}<br>
Additional Comment : {{q.COMMENT}}
</div>
</div>
</div>
You can use \n to concatenate words and then apply this style to container div.
style="white-space: pre;"
More info can be found at https://developer.mozilla.org/en-US/docs/Web/CSS/white-space
<p style="white-space: pre;">
This is normal text.
</p>
<p style="white-space: pre;">
This
text
contains
new lines.
</p>
I could be wrong because I've never used Angular, but I believe you are probably using ng-bind, which will create just a TextNode.
You will want to use ng-bind-html instead.
http://docs.angularjs.org/api/ngSanitize.directive:ngBindHtml
Update: It looks like you'll need to use ng-bind-html-unsafe='q.category'
http://docs.angularjs.org/api/ng.directive:ngBindHtmlUnsafe
Here's a demo:
http://jsfiddle.net/VFVMv/
You need to either use ng-bind-html-unsafe ... or you need to include the ngSanitize module and use ng-bind-html:
with ng-bind-html-unsafe
Use this if you trust the source of the HTML you're rendering it will render the raw output of whatever you put into it.
<div><h4>Categories</h4><span ng-bind-html-unsafe="q.CATEGORY"></span></div>
OR with ng-bind-html
Use this if you DON'T trust the source of the HTML (i.e. it's user input). It will sanitize the html to make sure it doesn't include things like script tags or other sources of potential security risks.
Make sure you include this:
<script src="http://code.angularjs.org/1.0.4/angular-sanitize.min.js"></script>
Then reference it in your application module:
var app = angular.module('myApp', ['ngSanitize']);
THEN use it:
<div><h4>Categories</h4><span ng-bind-html="q.CATEGORY"></span></div>
Why so complicated?
I solved my problem this way simply:
<pre>{{existingCategory+thisCategory}}</pre>
It will make <br /> automatically if the string contains '\n' that contain when I was saving data from textarea.
I've used like this
function chatSearchCtrl($scope, $http,$sce) {
// some more my code
// take this
data['message'] = $sce.trustAsHtml(data['message']);
$scope.searchresults = data;
and in html I did
<p class="clsPyType clsChatBoxPadding" ng-bind-html="searchresults.message"></p>
thats it I get my <br/> tag rendered
You can also use:
String.fromCharCode(10);
with CSS
white-space: pre-line;
Here si working example:
https://jsfiddle.net/Nxja/3xtcqdej/1/

Categories