I'm using an ExtJS grid panel. This grid has more than 20 rows of info and I want to search in each row for an icon that represents active mode, using WebdriverIO as a test driver.
How can I search in each row till the test driver finds the first active icon? (Note: the grid I'm testing is hosted on alegra.com).
Consider the following HTML print-screen:
It's hard to know exactly how to do it without knowing which locator you are using but if you first get a list of the rows and then filter them and grab the first match it should do what you are looking for.
public static get rows() { return browser.elements('#someTableId > table > tbody > tr'); }
public static getFirstMatch() {
return this.rows.value.filter((row: WebdriverIO.Element) =>
browser.elementIdElement(row.ELEMENT, 'someLocator').value)[0];
}
This is how i did it
var icon_type = 'delete';
it('Se elimina una factura', function(){
//rellenamos el array de elementos del grid
var elements = browser.getAttribute('#gridInvoices #gridview-1047-table tbody tr .action-icons img:nth-child(7)','class');
//Busca la primera coincidencia en el array con type
var row_num = elements.indexOf(icon_type);
if(row_num === -1){
throw new Error('No se encontraron botones activos del tipo "Eliminar" en todo el grid' )
}else{
$$('#gridInvoices #gridview-1047-table tbody tr')[row_num].click('.action-icons [title="Eliminar"]');
browser.click('=Sí')
};
});
Related
first time using jsPDF.
I'm trying to export some data via PDF, however when I try to export the array it gives me an error. I have ASSUMED you export arrays using doc.table because I can't get to find any documentation, there's a tag for it in stackoverflow for questions but didn't find anyone with the same question neither.
This is what I have so far
const generatePDF = () => {
var doc = new jsPDF('landscape', 'px', 'a4', 'false');
doc.addImage(AIBLogo, 'PNG', 250,10,100,100)
doc.setFont('Helvertica', "bold")
doc.text(60,150, "Informacion del Pedido");
doc.setFont('Helvertica', "Normal")
doc.text(60,170, "Estado del Pago: "+estadoDePago)
doc.text(60,190, "Estado de Disponibilidad: "+estadoDeDisponibilidad)
doc.text(60,210, "Total del Pedido: "+total)
doc.text(60,230, "Total Pagado: "+totalPagado)
doc.setFont('Helvertica', "bold")
doc.text(360,150, "Informacion del Estudiante");
doc.setFont('Helvertica', "Normal")
doc.text(360,170, "Nombre del Estudiante: "+nombre)
doc.text(360,190, "Escuela: "+escuela)
doc.text(360,210, "Estado del Pago: "+grado)
doc.text(360,240, "Direccion de Entrega: Retirar en institución")
doc.table(100,100, librosData)
doc.save(id+".pdf")
}
Excluding the table bit it prints out like this:
I would like to add the DataTable after all that info and make new pages if is out of bounds cause table can be up to 20 items.
UPDATE
I have try the following but is not working neither I got it from here: StackOverflow Answer
var col = ["Descripcion", "Tipo", "Editorial","Precio"]
row = []
for (let i = 0; i < librosData.length; i++){
var temp = [librosData[i].descripcion, librosData[i].tipo, librosData[i].editorial, librosData[i].precio];
row.push(temp)
}
doc.autoTable(col,row, {startY:380});
doc.save(id+".pdf")
I know all the data is coming correctly this is how the row is printing:
Any help or documentation is appreciate it.
Final Update
To fix the issue that says autotable is not a function just
Solution: StackOverflow
In the end to make the table I recommend this:
To do the table: How to export a table with jsPDF
To fix the compatibility: autoTable is not a function
To fix "deprecated autoTable initiation":
Initialize your autoTable the following way
import autoTable from 'jspdf-autotable'
autoTable(doc, {
head: [col],
body: row
})
I have a select that now needs to select and save more than one option. His FrontEnd part is already done, but BackEnd is not.
I need this select to save the selected values, for that it will need to loop the code, because at the moment it only saves one value.
However I don't know how to loop this code so that it saves all values and stops giving an error.
Screen with the selected values and their codes:
enter image description here
Select html code:
<div class="form-group pmd-textfield">
<label for="TipoPenalAntecedenteCriminal" class="espacamentoLabels">
Tipo Penal Principal
</label>
<select asp-items="Model.ListTipoPenal"
name="COD_TIPO_PENAL_PRINCIPAL"
id="TipoPenalAntecedenteCriminal"
form="formAntecedenteCriminal"
class="select-codigo" multiple
onchange="mostrarOutroDeCombo(this, 'OutroTipoPenalAntecedenteCriminal');">
<option value="">Selecione a relação</option>
</select>
</div>
Code Controller:
this is the code that I need to loop to save all values
[HttpPost]
public JsonResult SalvarAntecedenteCriminal(IFormCollection form)
{
#region GET DADOS DO USUARIO
var identity = (ClaimsIdentity)User.Identity;
string usuarioLogado = identity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
#endregion
_logger.LogInformation(EventosLog.Get, "Usuário: {Usuario} | Salvando Antecedente criminal de autor com o código {codigo}.", usuarioLogado, form["COD_AUTOR"]);
string codAntecedente = string.IsNullOrEmpty(form["COD_AUTOR_ANTECEDENTES_CRIMINAIS"]) ? "0" : (string)form["COD_AUTOR_ANTECEDENTES_CRIMINAIS"]
, codUF = string.IsNullOrEmpty(form["COD_UF"]) ? "0" : (string)form["COD_UF"]
, codTipoPenal = string.IsNullOrEmpty(form["COD_TIPO_PENAL_PRINCIPAL"]) ? "0" : (string)form["COD_TIPO_PENAL_PRINCIPAL"];
DateTime? ocorrenciaData = string.IsNullOrEmpty(form["OcorrenciaData"]) ? null : (DateTime?)DateTime.Parse(form["OcorrenciaData"]);
var antecendeteCriminal = new AutorAntecedentesCriminaisModel
{
COD_AUTOR = int.Parse(form["COD_AUTOR"]),
COD_AUTOR_ANTECEDENTES_CRIMINAIS = int.Parse(codAntecedente),
OcorrenciaNumero = form["OcorrenciaNumero"],
COD_UF = int.Parse(codUF),
OcorrenciaData = ocorrenciaData,
COD_TIPO_PENAL_PRINCIPAL = int.Parse(codTipoPenal),
OutroTipoPenal = form["OutroTipoPenal"]
};
try
{
antecendeteCriminal.COD_AUTOR_ANTECEDENTES_CRIMINAIS = antecendeteCriminal.Insert(usuarioLogado);
}
catch (Exception excecao)
{
_logger.LogError(EventosLog.FormularioSalvarErro, excecao,
"Usuário: {Usuario} | Falha ao salvar antecedente criminal de autor com o código {codigo} devido à exceção.",
usuarioLogado, form["COD_AUTOR"]);
if (_env.IsDevelopment())
throw;
return Json(null);
}
return Json(antecendeteCriminal);
}
Code image, the part in yellow and where the error hits when saving.
In "COD_TIPO_PENAL_PRINCIPAL = int.Parse (codTipoPenal)," it is receiving the values, but it is not saving.
enter image description here
The COD_TIPO_PENAL_PRINCIPAL should be a int array if you wany to save all the values.
public int[] COD_TIPO_PENAL_PRINCIPAL { get; set; }
In my app I receive some objects in Json. I want to create one panel that shows a single object. If I receive 2 objects, create 2 panels with his content and if I receive 100: 100 panels.
I tried to use a for with .add and .doLayout but never shows any panel. In my console shows the creation of panels, but never renders into my principal panel container. What im doing wrong?
thats my code:
success : function(response) {
var jsonResp = Ext.util.JSON
.decode(response.responseText);
// Ext.Msg.alert("Info", "UserName from Server : " + jsonResp.message);
// Limpiamos el array para tener solo las propiedades que se usarán
jsonResp.forEach(function(currentItem) {
delete currentItem["cls"];
delete currentItem["estandar"];
delete currentItem["iconCls"];
delete currentItem["leaf"];
delete currentItem["objetivo"];
delete currentItem["observaciones"];
delete currentItem["porcentaje"];
delete currentItem["salvaguardas"];
delete currentItem["tieneDocs"];
delete currentItem["tipoNombre"];
delete currentItem["responsable"];
delete currentItem["responsableId"];
delete currentItem["idReal"];
delete currentItem["tipoNombre"];
delete currentItem["tipo"];
delete currentItem["calculado"];
delete currentItem["text"];
});
var children = [];
console.log(jsonResp);
var sumarvariable = 0;
//add children to panel at once
for ( var i in jsonResp) {
if (i < jsonResp)
var panel = new Ext.Panel({
id : 'pregunta' + sumarvariable,
html : sumarvariable
})
console.log(panel)
Ext.getCmp("contenedor").add(panel);
Ext.getCmp("contenedor").doLayout();
sumarvariable++;
}
},
Change that for and use a .forEach like you're using in your jsonResp.forEach under your second comment. This code creates one panel and add it to your "contenedor".
//Create Panel with every object
var i = 0;
jsonResp.forEach(function(currentItem) {
i++;
var panel = new Ext.Panel({
id: 'jsonObject' + i,
html: 'Object' + i
})
//Add to your object "contenedor"
Ext.getCmp("contenedor").add(panel);
});
//Force reload and shows every panel
Ext.getCmp("contenedor").doLayout();
I'm working with arcgis Javascript Api 3.7 (wich includes dojo 1.9.1), and I have been developing a custom templated dijit that has two filteringSelect controls, the first one gets pupulated correctly, and i have a second one that gets populated when the user selects one item from the first one setting its data store at that particular moment. this second filteringSelect gets correctly populated everytime, but something happens with the onchange event, because the function handler never gets fired, I need to do some other staff on the onchange event of the second FilterinSelect.
It seems something gets messed up with the second filteringSelect (guessing something with the handler context) but I can't figure it out yet.
My two filtering controls template declaration (part of my dijit html template:
<tr>
<td>
Capa:
</td>
<td>
<input data-dojo-type="dijit.form.ComboBox" name="layerDijit" id="layerDijit"
data-dojo-props="autoComplete:true, required:true, searchAttr:'name', style:'width:100%;'"
data-dojo-attach-point="layerDijit" data-dojo-attach-event="change:_handleLayerSelected"/>
</td>
</tr>
<tr>
<td>
Campo:
</td>
<td>
<input data-dojo-type="dijit.form.FilteringSelect" name="fieldDijit" id="fieldDijit"
data-dojo-props="autoComplete:true, required:true, searchAttr:'name', style:'width:100%;'"
data-dojo-attach-point="fieldDijit" data-dojo-attach-event="change:_handleFieldSelected"/>
</td>
</tr>
Dijit JS Script:
The code that populates the first Filtering Select
postCreate: function() {
this.inherited(arguments);
....
this.rootMapLayer = this.map.getLayer("ELAPAS");
if (this.rootMapLayer.loaded){
this.listLayers(this.rootMapLayer);
}
else{
this.rootMapLayer.on("load", lang.hitch(this, this.listLayers));
}
//enlace de eventos (tested this, and it doesn't work for the second filtering select either)
//this.fieldDijit.on('change', lang.hitch(this, this._handleFieldSelected));
//this.layerDijit.on('change', lang.hitch(this, this._handleLayerSelected));
},
listLayers: function() {
var layerInfos = [];
layerInfos = array.filter(this.rootMapLayer.layerInfos,function(info,index){
return info.subLayerIds === null;
});
if(layerInfos.length === 0) {
console.error("No se encontro ninguna capa para el servicio de mapa seleccionado");
return;
}
var layersStore = new Memory({
data: layerInfos
});
this.layerDijit.set('store', layersStore);
},
The code that handles the selection change in the first filteringSelect called layerDijit and loads the data for the second one (FieldDijit):
_handleLayerSelected: function () {
var selectedLayer = this.layerDijit.item;
if(this.getSelectedLayerUrl() === null) {
return;
}
//Se limpia el campo actual
this.fieldDijit.set("value", "");
//Se arma la url del layer específico para traer la información de la capa (sus campos)
var layerUrl = this.rootMapLayer.url + "/" + selectedLayer.id;
esri.request({
url: layerUrl,
content: {
f: "json"
},
handleAs: "json",
callbackParamName: 'callback',
load: lang.hitch(this, '_handleLayerInfo'),
error: lang.hitch(this, '_handleLayerInfoError')
});
},
_handleLayerInfo: function(data) {
var layerInfo = data;
if (!layerInfo.fields) {
console.error("No se pudo obtener la información de los campos de la capa");
return;
}
var fieldsStore = new Memory({
data: layerInfo.fields
});
this.fieldDijit.set('store', fieldsStore);
},
getSelectedLayerUrl: function(){
var selectedLayer = this.layerDijit.item;
if(!selectedLayer) {
return null;
}
//Se arma la url del layer específico para traer la información de la capa (sus campos)
return this.rootMapLayer.url + "/" + selectedLayer.id;
},
_handleLayerInfoError: function(err){
console.error(err);
},
The function that doesn't get fired, the one that is supossed to handle se change event of the second filtering select:
_handleFieldSelected: function () {
alert("doesn't get fired");
/*var selectedField = this.fieldDijit.item;
if(!selectedField) {
return;
} */
},
Could you give me some advice about this problem?, What am I doing wrong?.
Thanks in advance
bishop, thanks for your answer, I think I wasn't clear with my question, I do understand that the "onChange" event is supposed to get fired when the user (or something in the background) changes the selected item in the FilteringSelect, so my problem was that when the user selects an item from the second FilteringSelect control its onchange event didn't get fired.
As you suggested I tryed a simpler example (with a hard coded Memory objects) and it did work, so I started to dig a little bit more and realized that the problem was with my memory object,
Aparently when you declare a Memory object you have to make sure that there is an ID filed in the array collection objects, like in the next example:
var stateStore = new Memory({
data: [
{name:"Alabama" id:"AL"},
{name:"Alaska", id:"AK"},
{name:"American Samoa", id:"AS"},
{name:"Arizona", id:"AZ"},
{name:"Arkansas", id:"AR"},
{name:"Armed Forces Europe", id:"AE"},
{name:"Armed Forces Pacific", id:"AP"},
{name:"Armed Forces the Americas", id:"AA"},
{name:"California", id:"CA"},
{name:"Colorado", id:"CO"},
{name:"Connecticut", id:"CT"},
{name:"Delaware", id:"DE"}
]
});
this.fieldDijit.set('store', stateStore);
When you don't explicitly tell it in the memory object declaration, it is asummed that there is a field called "id". In my case, the array that I assing to the memory object in the second filteringSelect didn't have a field called "id"
so I changed:
var fieldsStore = new Memory({
data: layerInfo.fields
});
for:
var fieldsStore = new Memory({
idProperty: "name", //added this
data: layerInfo.fields
});
and now the event gets fired when the selected item in the second filterin select changes.
Based on what I'm reading, I think you're expecting this code:
this.fieldDijit.set('store', fieldsStore);
to cause the second select in your co-dependent select arrangement to fire its change event -- after all, the select has "changed" in the sense that it has a different store.
But that's not what the change event means. The change event means the user has changed the selected value. So after setting a new store, if you select a value in the second drop down, your change handler should fire.
Here's an example that I think reduces yours to its simplest elements. Notice how when you select the first box's value, the second's store changes but its onchange event does not fire (as expected). But when you select the second box's value, its onchange does fire (as expected):
<!DOCTYPE html>
<html>
<head>
<link href='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css' rel='stylesheet' type='text/css' />
<script src='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'></script>
</head>
<body class='claro'>
<div data-dojo-id='s1' data-dojo-type='dojo/store/Memory' data-dojo-props='data:[{id:1,name:"A"}]'></div>
<div data-dojo-id='s2' data-dojo-type='dojo/store/Memory' data-dojo-props='data:[{id:1,name:"C"}]'></div>
<select data-dojo-id='first' data-dojo-type='dijit/form/ComboBox' data-dojo-props='store:s1'>
<script type='dojo/method' event='onChange'>
second.set('store', s2);
</script>
</select>
<select data-dojo-id='second' data-dojo-type='dijit/form/ComboBox'>
<script type='dojo/method' event='onChange'>
alert('I am changed');
</script>
</select>
<script type='text/javascript'>
require(['dojo/ready', 'dojo/parser'], function (ready, Parser) {
ready(function () {
Parser.parse().then(function () {
});
});
});
</script>
</body>
</html>
If I'm not understanding the error you're describing, can you send a simpler test case?
Hello I'm having trouble with the function setUpTranslation().
//The purpose of this function is to place the French phrases into the document and set up the event handlers for the mousedown and mouseup events.
//These are the arrays of the French phrases and English phrases that I have do place into the document:
var english = new Array();
english[0] = "This hotel isn't far from the Eiffel Tower.";
english[1] = "What time does the train arrive?";
english[2] = "We have been waiting for the bus for one half-hour.";
english[3] = "This meal is delicious";
english[4] = "What day is she going to arrive?";
english[5] = "We have eleven minutes before the train leaves!";
english[6] = "Living in a foreign country is a good experience.";
english[7] = "Excuse me! I'm late!";
english[8] = "Is this taxi free?";
english[9] = "Be careful when you go down the steps.";
var french = new Array();
french[0] = "Cet hôtel n'est pas loin de la Tour Eiffel.";
french[1] = "A quelle heure arrive le train?";
french[2] = "Nous attendons l'autobus depuis une demi-heure.";
french[3] = "Ce repas est délicieux";
french[4] = "Quel jour va-t-elle arriver?";
french[5] = "Nous avons onze minutes avant le départ du train!";
french[6] = "Habiter dans un pays étranger est une bonne expérience.";
french[7] = "Excusez-moi! Je suis en retard!";
french[8] = "Est-ce que ce taxi est libre?";
french[9] = "Faites attention quand vous descendez l'escalier.";
//function I'm having trouble with
function setUpTranslation(){
var phrases = document.getElementByTagName("p");
for (i =0; i<phrases.length; i++){
phrases[i].number =i;
phrases[i].childNodes[1].innerHTML =french[i];
phrases[i].childNodes[1].onmousedown =function(){
swapFE(event);
phrases[i].childNodes[1].onmouseup =function(){
swapEF(event);
};
};
}
//Below are the other two functions swapFE() and swapEF(). The purpose of the function swapFE() is to exchange the French phrase for the English translation
//The purpose of the function swapEF() is to exchange the English translation for the French phrase.
function swapFE(e){
var phrase =e.srcElement;
var parent =phrase.parentNode;
var idnum =parent.childNodes[0];
var phrasenum =parseInt(idnum.innerHTML)-1;
phrase.innerText =english[phrasenum];
}
function swapEF(e){
var phrase =e.srcElement;
var parent =phrase.parentNode;
var idnum =parent.childNodes[0];
var phrasenum =parseInt(idnum.innerHTML)-1;
phrase.innerText =french[phrasenum];
}
//Not sure if these are right. Thanks in advance!
Assuming that your HTML looks like this
<p><span>1</span><span></span></p>
<p><span>2</span><span></span></p>
...
<p><span>10</span><span></span></p>
Then all you need to do is to add the curly bracket after swapFE(event); (points for Mr Plunkett) and replace getElementByTagName with getElementsByTagName (you're missing an 's' in there).
One additional thing to note: If the English phrase is shorter than the French, the container might shrink when the onmousedown event fires. If this shrinkage causes the mouse cursor to be positioned outside the container, the subsequent onmouseup event will not be triggered. Of course, if you are using block elements (e.g. a <div>) instead of my assumed <span>, that likely isn't an issue. In any case, it's probably better to attach the event listeners to the <p> tags instead.