AngularJs Filters - javascript

I'm writing a module, using a custom filter, and I noticed something weird. if I use console.log() inside a filter, it logs the value twice, even though I call it only once. Is there a way to log it only once? Does that mean the code inside the filter gets executed twice?
Here's the filter:
.filter('arrayToSentence', function($sce, $rootScope) {
return function(array, index) {
console.log(index);
var i, word, sentence = '<span style="color:red;">';
for (i = 0; i < array.length; i++) {
if (i < array.length - 1) {
sentence += array[i] + '&bnsp;';
} else {
sentence += array[i];
}
}
sentence = sentence += '</span>'
return $sce.sentence;
}
})
The console.log(index) is logging twice. I need to make sure that my filter logic will not be duplicating anywhere, as further down I need to compare two arrays (the one being filtered, and another one to colour the differences between them, like missing word, or word mismatch).
[EDIT]
It is pointed out to me that my question is a duplicate, of this
Yet the original question doesn't answer how to avoid this issue, but I believe #defaultcheckbox provided a fulfilling answer.

Are you using the filter in the DOM with piping, or are you using it in the controller? Using a filter in the DOM will always be "slower" than using one in the controller, but more importantly (and possibly related to your case) DOM filters always run twice.
source: https://toddmotto.com/use-controller-filters-to-prevent-digest-performance-issues/

Related

javascript use console.log without moving to new line

I am new to js and hope this is not too trivial, but I am unable to find any help on the net.
I wish to output to console.log and prevent moving to a new line, so the next time the output will be appended to the same line. ie,
"use strict";
for (let i = 0; i<=9;i++){
console.log(i); // here i would like to freeze the output so the result is 0123456789 on one line, rather than those digits in a column.
}
I have seen fixes involving assigning the outputs to a string and printing in 1 hit, but that seems incredibly crude. Even in Fortran 4 as I recall in the '70s, you could prevent moving to a new line before printing again, so I think I am missing something fundamental. Also I cannot find any general help on formatting numerical output in javascript. Can someone point me in the right direction?
Thanks
Unfortunately, the console.log() method will only write out a string to a single line and doesn't support the appending behavior you are looking for.
As you detailed in your original post, you could accomplish writing the final result out through the use of a variable (i.e. displaying the final concatenated string), but not continually appending to the same line within the console itself as the loop is being iterated over.
Alternative Grouping Option
The concept of grouping entries is supported, which is obviously very different than your original ask, but it may be worth considering as mentioned in the documentation for console.group() and might look something like this:
var rollingConcatenation = '';
console.group("Looping Group Example");
for (let i = 0; i<=9;i++){
rollingConcatenation += i;
console.log(rollingConcatenation);
}
console.groupEnd();
This can give your console the following appearance, which can help with readability (depending on your use cases):
Do It Yourself Implementation
Another option might be to store your current console value within a variable and at clear it and rewrite the updated values out. Depending on your very specific use cases, you could achieve the behavior you are looking for using something like this crude implementation:
// Define a custom console
var customConsole = {
// Store a reference to your backing value
tempValue: '',
// Always write out the most recent value
log: function(msg) {
this.tempValue += msg;
console.clear();
console.log(this.tempValue);
},
// A clear method to clear the backing console
clear: function() {
this.tempValue = '';
console.clear();
}
}
for (var i = 0; i < 10; i++) {
// Use your custom console instead of the normal one
customConsole.log(i);
}
Take a new variable outside the loop and then prepare that string inside the loop and then you can console.log() outside the loop.
var str = '';
for (let i = 0; i <= 9; i++) {
str += i;
}
console.log(str);

What would cause slice() to work, but splice() to fail?

I am working on a sheet that contains job description information, including an Overview and Responsibilities. The source data is not exact, but it roughly has the Overview in one cell of a column, and each Responsibility in additional cells in the same column. I am writing the Overview (which I am determining based on character count) in one results column, and building an unordered list with each the Responsibilities into another results column.
My source isn’t always perfect though. I have situations where the first Responsibility is included in the same cell as its corresponding Overview. I can recognize that by the text, and have an indexOf() statement written to do that.
When I use a slice() method, the script is correctly indicating the text that is occurring after the appropriate index. But what I need is to use the splice() method, so that I can remove that text from the source data before creating the results data. However, when I change the statement from slice() to splice(), I’m getting an error: “TypeError: Cannot find function splice in object {beginning text of the cell}”
for(i=0; i<data.length; i++) {
var iRow = data[i];
if(iRow[12].length > 250) { // this is an overview
if(iRow[12].indexOf("What you’ll do")>-1) { // is there a responsibility at the end of the overview?
var startIndex = iRow[12].indexOf("What you’ll do");
// this is the line that works for slice(), but not splice()
var txt = iRow[12].splice(startIndex, 26); // splice out the end of text, starting at the index.
data[writeRow][18] += iRow[12]; // write the overview, without the added responsibility
data[writeRow][19] += "<li>" + txt + "</li>"; // add the extracted responsibility to its list
} else { // these is no responsibility added to the end of the overview
data[writeRow][18] += iRow[12]; // write the overview
}
} else { // this is a responsibility
data[writeRow][19] += "<li>" + iRow[12] + "</li>"; // add it to the list
}
}
There's obviously a lot more going on (defining var data, var writeRow, initiating the , etc) which all works fine. I’m sure that I’m just being an idiot somewhere. But can someone help me figure out why slice() works here, but splice() doesn’t?
splice is an array function. slice is both, an Array function and a String function.
References
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice

JavaScript - adding spaces after push in empty array & one checkbox is free

Here's my codepen:
https://codepen.io/CwittleZ/pen/vdzazO?editors=1010
When you click on the meat selection, it gets pushed into an array and then displayed, but there's no space between selections. How would I go about adding that space?
function meatSelected() {
var meat = [];
var meatChecked = document.querySelectorAll(
"input[name=meat_options]:checked"
);
for (var i = 0; i < meatChecked.length; i++) {
meat.push(meatChecked[i].value);
}
console.log(meat);
document.getElementById("meat").innerHTML = meat;
}
Also, I need one of the meats to be free, but anything over will be extra. I don't know how or where to add that 'if meat checked is > 1, all other meats will be an additional $1 each.' Is there somehow a way to access the function meatSelected for that purpose? I'm just starting out with JavaScript, so please no jQuery and simple terms if possible, even if it is a longer code. I just want to be able to understand why it works.
if (document.getElementById("pepperoni").checked) {
add += 1;
}
if (document.getElementById("sausage").checked) {
add += 1;
}
if (document.getElementById("canadian_bacon").checked) {
add += 1;
}
if (document.getElementById("ground_beef").checked) {
add += 1;
}
if (document.getElementById("anchovy").checked) {
add += 1;
}
if (document.getElementById("chicken").checked) {
add += 1;
}
The answer is in the line 83 in JavaScript part of your example. In line 77, you made an array of possible meats. Then, you just used this array and attached it to innerHTML as it is, so that the browser has to make it a string. Unfortunately, it doesn't care about spaces.
So, just change that line to this:
document.getElementById("meat").innerHTML = meat.join(", ");
It will use your already made array and convert it directly into string, with ", " between each of its children.
And to your second question, there are more possible solutions, I've implemented the easiest one in this codepen: https://codepen.io/anon/pen/ddqqyY?editors=1010.
Just sum up the number of already selected meats and if it's larger than zero, subtract 1 from your total.
I'd wrap each one of your selections in a "span", and add a margin after. You're using innerHTML, so you can just do it that way. It'll provide more flexibility than trying to style the plain-text.
document.getElementById("meat").innerHTML = meat.map(m => ` ${m}`);
here is your codepen that is modified https://codepen.io/jayas/pen/bLxjXo?editors=1010
edit as per suggestion
The ${m} together with the enclosing ticks `` used in the statement is called a template literal. Template literals can contain placeholders
and these are indicated by the dollar sign and curly braces ${}.
[].map(callBackFunc) used above is a method that creates a new array with each element being the result of the callback function.

Removing '<and text within those>' from a string in javascript

I'm receiving an array of strings from a REST api call, and the strings have some html tags in them, for example:
Bard's opponents can also travel through his Magical Journey doorways. You can follow him, if you think it's safe.</li>
You can crush Bard's healing shrines just by walking over them. Don't let his allies take them without a fight.
Bard's ultimate, Tempered Fate, affects allies, enemies, monsters, and turrets alike. Sometimes it can be to your advantage to jump into it!</li>
Each line is a string, and two of them have an </li> tag at the end.
I tried writing a function that receives such an array, and returns a corrected array. Problem is, when I use it, the console in my website shows some weird errors with the strings from the array, and I've realized my function was the cause.
That is the function:
modal.removeBracketsFromArray = function (array) {
if (array == undefined)
return array;
function removeBracketsText(text) {
return text.replace(/<[^>]*>/g, '')
};
var newArray = [];
for (var i = 0; i < array.length; i++) {
newArray.push(removeBracketsText(array[i]));
}
return newArray;
};
It seems to do the work, but it somewhy messes up when using it in an ng-repeat attribute.
This is an use example:
<champion-ally-enemy-tips allytips="modalCtrl.removeBracketsFromArray(modalCtrl.champ.allytips)"
enemytips="modalCtrl.removeBracketsFromArray(modalCtrl.champ.enemytips)">
</champion-ally-enemy-tips>
which then moves to:
<ul>
<li ng-repeat="enemytip in enemytips"><h6>{{enemytip}}</h6></li>
</ul>
When I remove the method call (like so), it doesn't show an error, but the tags remain:
<champion-ally-enemy-tips allytips="modalCtrl.champ.allytips"
enemytips="modalCtrl.champ.enemytips">
</champion-ally-enemy-tips>
Is my function doing something weird without realizing it? thanks for helping
This is a pastebin of the errors I receive: LINK
Instead of messing with the array, how about creating a custom filter to strip out the HTML on display?
.filter('removeHTML', function() {
return function(input) {
return input.replace(/<[^>]*>/g, '');
}
})
Then change your display inside the ng-repeat to:
<h6>{{enemytip | removeHTML}}</h6>

JS For Loop Stopping Early after Calling Function

I have a Javascript Array that holds the contents of a page. In order to draw all the objects in the right places when the page loads I loop over the array and pull out the elements. This worked very well until I allowed the objects to have children within them.
The current array structure is
0-> {elements=[] frame={I keep the frame attributes here with key value pairs}}, 1-> {elements=[] frame={}}
However, I just started adding sub-elements to the elements array in each object. So now I have to loop through/draw each element, check to see if there are any children and if so then I have to draw them too.
The problem I'm having is that after I loop through the first 0 object and it's children the for loop stops running. Is it because I'm calling the same function multiple times? I've done that before so I don't think that's what is happening.
this.run_loop = function (spawn, dom) {
console.log(spawn)
alert(spawn.length)
for (i = 0; i < spawn.length; i++) {
console.log(spawn[i])
//alert("i one")
var newdom = dom + "_" + i;
this.synthesize_elements(spawn[i], dom, newdom)
if (spawn[i].hasOwnProperty('elements')) {
//alert("FOUND")
var newarray = spawn[i]['elements'];
if (newarray.length > 0) {
this.run_loop(newarray, newdom)
}
}
}
}
This is a little old but I encountered a similar issue and found my way here, but I figured it out and thought I'd post the solution if anyone else came across this. The issue in my case (and it looks like in your case as well though I can't be sure) was in the declaration of the for loop:
for (i = 0; i < spawn.length; i++)
You're not declaring that i is a new var. so if anything inside the
this.run_loop(newarray, newdom)
function also manipulates a counter variable called i that isn't declared a new var, it will also change the one in your outer scope, and kick you out of the loop if it goes over the length of spawn
just always declare:
for (var i; i< spawn.length; i++)
in your loops or make sure your counters are unique.

Categories

Resources