Edit html text value using directives - javascript

In my app, I'm using some variable which contain a code instead of the value itself. This code matches one field of an array which items contain the code with the matching value. What I could do to display the name is a loop to find the value based on the code. But as my app has a lot of these, I would need to do it for each value.
Here is the array:
[{code: 'PN', name: 'Panasonic'}, {code: 'SN', name: 'Sony'}]
Therefore, I thought using an attribute would be much better and cleaner. I would like to put the following jade: div(json-array={{televisions}}) {{ code }} and change the displayed code with televisions[X].name. The problem is that I'm not so familiar with directives.
I tried to use the link function to catch the value (code) and the binded variable array ({{televisions}}) but I encountered two problems:
How can I modify the div value without modifying the binded variable (code)?
How do I get the array (televisions) within my directive?

I still wouldn't use a directive for that. It is a simple presentation issue and can be easily (and declaratively) handled in the view (yet the question lacks all necessary info in order to provide the most appropriate solution).
<div>{{getTelevisionName(tv.code)}}</div>
$scope.getTelevisionName = function (code) {
for (var i = 0; i < $scope.televisions.length; i++) {
var tv = $scope.televisions[i];
if (tv.code === code) return tv.name;
}
return '';
};

Related

Assign HTML elements ID to document.queryselector shorthand variables in a loop

I am new to Javascript development.
I am trying to assign HTML elements IDs stored in an array to shorthands to be used in my function later.
So that instead of writing :
let addprop = document.querySelector(`#addprop`);
let readprop = document.querySelector(`#readprop`);
let editprop = document.querySelector(`#editprop`);
let footer = document.querySelector(`#footer`);
let association = document.querySelector(`#association`);
I can attribute elements ids that i store in an array like this :
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"] ;
arrayElements.forEach(el => { return(new Function (`${el} = document.querySelector("#${el}");`)()); });
Now, this bit of code works but from what I read here :
Execute JavaScript code stored as a string
This is probably not a good way to do it and also declares global variables.
One problem I encountered is that if I try to directly execute the assignment like this :
el = document.querySelector(`#${el}`);
Then the el value takes the value of the named access ID element (https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object) and breaks the code.
So I resorted to generate a string first then execute it.
I could simply assign each shorthand manually but I spent way too much time trying to make this work and am now left curious as to what would be a good solution or approach for this.
And would the scope limitations for loops simply forbid me to do this without using global variables ?
edit : switched the working code in one line
Possible answer :
1 - does it matter to declare global variables like that ? As these variables already exist globally because of browsers named access for elements IDs.
2 - By kiranvj's answer, a solution can be to store in an object structured as keys being the shortcuts and the full strings being the values, and calling the shortcuts with the object[key] method ; or using destructuring to assign the values to variable directly with :
const {addprop, readprop, editprop, idfooter, assocpatients} = elements;
I feel like I am missing something on this last one but it also seems to work.
In the end I will stick with my first code as condensing the function in one line seems to negate the risks of cross site scripting (?), and global values for the variables assigned though this method anyway already exist because of named access.
You can create a dictionary with all the elements with ID and then destroy it into your variables, ignoring the unused ones.
function getAllElementsWithId() {
let elements = {}
for (let el of document.querySelectorAll('[id]')) {
if (!(el.id in elements)) {
elements[el.id] = el
}
}
return elements
}
let { addprop, readprop, editprop, footer, association } = getAllElementsWithId()
This uses document.querySelectorAll (link to MDN) to get all elements with an ID. Notice that for big pages this could be a performance issue.
Also, what you would usually do is to add them into a container, in this case it seems like a dictionary.
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"]
let elementsId = Object.fromEntries(arrayElements.map(id => [id, document.getElementById(id)]))
This uses Object.fromEntries (link to MDN) to generate the dictionary. Also I'm using document.getElementById (link to MDN) instead of document.querySelector so you don't need to add the hashtag before the id.
If you are concerned about global scope, you can try something like below. Use forEach instead of map . map also work but since you are not handling the return of map, forEach would be a better choice.
let arrayElements = ["addprop", "readprop", "editprop", "footer", "association"];
let elements = {};
arrayElements.forEach(el => elements[el] = document.querySelector(`#${el}`));
// access variables like elements.ID-NAME
console.log(elements);
<div id="addprop"></div>
<div id="readprop"></div>
Object destructing can be used if you know the object key name.
example : let {addprop} = element;
Another thing which you might be interested is Automatic global variables
This means a new variable (scoped to window) with the name of element id is created for all the elements in page. See the html5 spec. I would not recommend using it though.
So you don't have to call like document.querySelector('addprop')
addprop variable will have the DOM object.
See this example
// these works due to automatic global varaibles binding
alert(addprop);
console.log(addprop);
<div id="addprop">Some contents</div>

Error with reformatting the way data has been passed into a function

I have the following code :
var games = ["game_1", "game_2","game_3"]
var players= [{name:"steve"},{name:"sparrow"},{name:"captain"}]
var incomingData= [{game_1:"basketball"},{game_2:"badminton"},{game_3:"pingpong"}]
//change format as shown below:
reformat=[ {name:"steve",game:"basketball"},{name:"steve",game:"badminton"},{name:"steve",game:"pingpong"}]
incomingData.map(incomingData=>{
games.map((game,i)=>{
players[i].game= incomingData.game
})
})
console.log(players) //​​​​​[ { name: 'steve', game: undefined },​​​​​​​​​​ { name: sparrow', game: undefined },​​​​​​​​​​ { name: 'captain', game: undefined } ]​​​​​
I am trying to learn about how to handle objects. I am getting undefined for the list of game inside the object. I understand this approach is wrong and would like to get some suggestions regarding how to go about changing the format to the required format.
incomingData.map((data, i) => {
players[i].game = data[ games[i] ];
});
You just need one loop.
This is what you need:
incomingData.map(data=>{
games.map((game,i)=>{
players[i].game=incomingData[i][games[i]]
})
})
You can play with it on jsfiddle.
So how does it work? Inside innermost function you already see all necessary data. All you need is to properly assing game attribute of i-th player. So you need to take i-th object from incomingData and then read attribute that is i-th element of games. So for instance for 0 element you want incomingData[0].game_1 that is equivalent to incomingData[0]["game_1"] and since "game_1" is dynamic you replace it with games[i] which leads to final incomingData[i][games[i]].
Note also that you have used formal parameter name of outer map with the same name as variable in scop effectively hiding it. You could access that hidden variable but simpler and cleaner is to give different name, hence renamed to data.
Surely it can be simplified as other users shown, my goal here was to simply fix assignment leading to undefined. Enough for learning fundamentals, for optimal code however see one loop receipt.
try this
var games = ["game_1", "game_2","game_3"]
var players= [{name:"steve"},{name:"sparrow"},{name:"captain"}]
var incomingData= [{game_1:"basketball"},{game_2:"badminton"},{game_3:"pingpong"}]
//change format as shown below:
var reformat=[ {name:"steve",game:"basketball"},{name:"steve",game:"badminton"},{name:"steve",game:"pingpong"}]
games.map((game,i)=>{
players[i].game= incomingData[i][game];
})
console.log(players)
}

Protractor code to extract multiple paragraph text

how to fetch the values of all paragraph (p) at a time ..
for example below is how my inspect view looks like
"testing sample one."
"testing sample two."
and below is my code sample to extract the value of id 'run'
browser.findElement(by.css('[id=run]')).getText()
this just extract the first value or I can modify and get the second value of id.. my need is I need to get both values at one go.. in the same line of code.. could you please advise
Though missing an html-example and a bit more description of what you like to extract, I'll give it a try.
In general you could/should use element.all(by.css()), aka $$(), instead of browser.findElements, except you know exactly, why you use findElements.
Read some details about the difference here.
Then as mentioned in a comment already, there is a findElements() (see API-Doc for findElements() here), returning an array of all values, matching the criteria. Just you can't immediately use getText() on it, as you get an array of elements and getText() requires a single element (see API-Doc for getText() here). Therefore you'd need to pass it through some loop.
Without knowing enough context here a small set of ideas to pick from.
var allP = new Array();
var allPString = null; //if one long string is desired
//here I'm using now element.all() instead of browser.findElements
var allPEl = $$('p#run'); //equal to element.all(by.css('p[id=run]')); //returns array of all found elements
var allPElBrowser = browser.findElements(by.id('run')); //returns array of all found elements
var i = allPEl.length();
var j = 0;
allPEl.each().getText().then(function(text){ //getAttribute('value') instead of getText(), if getText doesn't work.
allP.push(text); //add it to Array
allPString += text+' '; //add to String with a space at the end
j++; //counter
if(i === j-1){continueTest()}; //call continuation at the end of last loop, due to asynchronous nature of 'then()'.
});
continueTest = function(){
allP.toString() //in case of comma separated list from Array is desired
// here comes the rest of your test case logic
};
Note, that I go with the assumption that you need resolved promises, so the content of your <p>'s to continue.
If you can continue just with the array of <p>-objects, which you later resolve within an expect() all you need is $$('p#id');.
If the solution doesn't work for you, let me know, what part is still missing or where problems occur.

syntax error in GAS script editor

I have an error in the following code and I can't find why...
Using UiApp I define a couple of ListBox like this in a for loop
var critGlist = app.createListBox().setName('critGlist'+n).setId('critGlist'+n).addChangeHandler(refreshGHandler).addChangeHandler(cHandlerG).setTag(listItem[n]);
I added a TAG to be able to retrieve a value in the handler function because when I add items to this list I do it like this :
for(var c=0;c<listItem[n].length;++c){
critGlist.addItem(listItem[n][c],c);// the returned value is c, the value shown is listItem[n][c]
}
Then in my handler function I retrieve the value c that is the index of an element of the array listItem[n]
Since I stored a stringified value of this array as a tag I have to retrieve the tag first and then using the index I get the desired value...
That's where it becomes problematic !
I tried the 3 following codes :
var idx = Number(e.parameter['critGlist'+c]);// this works and I get the index
var item = e.parameter.critGlist0_tag.split(',')[idx];// this also works for a fixed index (0 here) but I need to use it in a for loop so I tried the code below
var item = e.parameter['critGlist'+c]_tag.split(',')[idx];// this generates an syntax error
// error message :"Signe ; manquant avant l'instruction. (ligne 129, fichier "calculatrice Global")"
// which means : missing ; before statement (line 129...
Am I missing something obvious ? How should I write it differently ?
Obviously it is the underscore that is not accepted... but how could I not use it ?
Well, I have a few other possibilities to get the result I want (using a hidden widget for example or some other temporary storage of even let the listBox return the value instead of the index) but still I'd like to know why this syntax is wrong ...
I'm not asking for a different code (as mentioned before there are a lot of other ways to go) , just some explanation about what is wrong in this code and this #!##å»ÛÁØ underscore ;)
You will need to put the whole property within the brackets as below
var item = e.parameter['critGlist'+c+'_tag'].split(',')[idx];// this generates an syntax error

javascript/jquery - dynamically add data by id to an array

Attempting to build a resume creator as a project for codeacademy.
I'm using a button to "save" the user's input to an array so it can later be appended into the resume.
However, I'm failing at getting the data to "save" to the array. I've looked at similar questions here on stackoverflow and I cannot for the life of me figure out what I am doing wrong.
here's my fiddle
specific code block I'm having trouble with:
$('#experiencesave').click(function(){
for (var i = 0; i < jobs; i++){
jobtitle.push = $('#jobtitle'+i).val();
}
$('#morejobs').append(jobtitle);
});
Well, .push [MDN] is a function which has to be called:
jobtitle.push($('#jobtitle'+i).val());
As an alternative solution, instead of using a for loop, you might want to use .map to collect the values:
var jobtitle = $('input[id^=jobtitle]').map(function() {
return this.value;
}).get();
I don't see a reason to give each of those input elements an ID though. Just give them a class. That makes it a bit easier to bulk-process them later. E.g. the selector could then just be $('input.jobtitle').

Categories

Resources