I'm learning CasperJS and want to try a simple, somewhat useful task. I'd like to make a pdf copy of my gas bill, but I can't even log into the website.
I'm a customer of CT Natural Gas. The URL is:
https://www.cngcorp.com/wps/portal/cng/home/mycng/customerWebAccess/
Logging in should be simple. It should just be my account number and last name.
My code is:
var start_url = "https://www.cngcorp.com/wps/portal/cng/home/mycng/customerWebAccess/"
var casper = require('casper').create()
casper.start(start_url, function() {
this.fill('formid', {
'input1id': '000000000000',
'input2id': 'LastName'
}, true);
this.capture('cng.png');
})
casper.run()
My "real" code uses the full ID shown in the site's HTML, not "formid" or "input1ID". I did not include the full ID in the sample code above because I was unsure what those ID's really were. They look something like: viewns_7_LOIGMC7IA21234QWERASDF1234_:custWebLogin. So much for a "simple" ID. Maybe this is something generated from a WebSphere product?
Anyway, the form is not found. I get:
CasperError: Errors encountered while filling form: form not found
I've also hacked it a bit and put this in my start to see what the form "looks like":
listItems = this.evaluate(function () {
var nodes = document.querySelectorAll('form');
return [].map.call(nodes, function(node) {
return node.id;
})
})
this.echo(listItems);
That returns:
,viewns_7_LOIGMC7IA21234QWERASDF1234_:custWebLogin
I think the form id is messing this up. Can anyone offer any suggestions?
Wait for the form to be loaded to fill the form using the selectors.Use have waitForSelector(),waitFor(),wait() etc other than waitForResource()
casper.start('your_url_here',function(){
this.echo(this.getTitle());
});
casper.waitForResource("your_url_here",function() {
this.fillSelectors('#loginform', {
'input[name="Email"]' : 'your_email',
'input[name="Passwd"]': 'your_password'
}, true);
});
I think the DOM/CSS3 Selectores doesn't work with this ID but it works with xpath :
// Create a function for selectXPath :
var x = require('casper').selectXPath
var start_url = "https://www.cngcorp.com/wps/portal/cng/home/mycng/customerWebAccess/"
var casper = require('casper').create()
casper.start(start_url, function() {
// Query xpath with fillSelectors
this.fill(x('//*[#id="viewns_7_LOIGMC7IA26I00I9TQ9SLI1B12_:custWebLogin"]'), {
'input1id': '000000000000',
'input2id': 'LastName'
}, true);
this.capture('cng.png');
})
casper.run()
Do you need the full ID? Because maybe something like that could work :
this.fill("form[id^='viewns_7_LOIGMC7IA21234QWERASDF1234']", {
'input1id': '000000000000',
'input2id': 'LastName'
Or
this.fill("form[id*='LOIGMC7IA21234QWERASDF1234']", {
'input1id': '000000000000',
'input2id': 'LastName'
Related
I have the following problem: after the input in a field I check if the value of the field is ok.
var oCheckGrossTons = oGrossTons.getValue();
var Msg = this.getResourceBundle().getText("validation.grossTons");
if (oCheckGrossTons < 500)
{var oMessage = new Message({
message: Msg,
type: MessageType.Error
});
sap.ui.getCore().getMessageManager().addMessages(oMessage);
So and now I want to color the border of this field in red so the user can see where he made a mistake.
So I tried to solve this with a jQuery. I created a CSS style like:
.rrpGrossTons {
border-color: "red"}
and my jQuery looks like this:
$("...").addClass('.rrpGrossTons');
So my main problem is, how do I get the ID of the field, because I think I have to enter the ID in the ("...") after the $ symbol. And is the Syntax of my jQuery correct?
You might want take a look at the valueState property of the InputBase (see an example)
Even better, you could use Constraints and let UI5 handle the validation for you.
<Input
textAlign="Right"
type="Number"
value="{
path: '/Grosston',
type: 'sap.ui.model.type.Float',
constraints: {
minimum: 0,
maximum: 500
}
}"/>
SAP has build in functionality for what you want to achieve:
// Mark control as not valid:
oGrossTons.setValueState(sap.ui.core.ValueState.Error);
// Reset the error state
oGrossTons.setValueState(sap.ui.core.ValueState.None);
So in your code it would be:
var oCheckGrossTons = oGrossTons.getValue();
if (oCheckGrossTons < 500) {
oGrossTons.setValueState(sap.ui.core.ValueState.Error);
var Msg = this.getResourceBundle().getText("validation.grossTons");
oGrossTons.setValueStateText(Msg);
var oMessage = new Message({message: Msg, type: MessageType.Error});
sap.ui.getCore().getMessageManager().addMessages(oMessage);
} else {
oGrossTons.setValueState(sap.ui.core.ValueState.None);
}
or use constrains as #A.vH mentionned in his answer.
Okay after a hard weekend I have found a solution for my Problem
var oCheckGrossTons = oGrossTons.getValue();
if (oCheckGrossTons < 500) {
this.setInvalidGrossTons(oGrossTons.getId());
} else {
this.removeErrorMsgForId(oGrossTons.getId());
}
and
setInvalidGrossTons: function (id) {
var oMessageProcessor = new sap.ui.core.message.ControlMessageProcessor();
var mainMsg = this.getResourceBundle().getText("validation.grossTons");
var msg = new sap.ui.core.message.Message({
message: mainMsg,
additionalText: "",
description: "",
type: sap.ui.core.MessageType.Error,
target: "/" + id + "/value",
processor: oMessageProcessor
});
this.bus.publish("rrp", "validationError", {
message: msg
});
},
so the only problem I am having now:
When I enter 100 tons i get the error Message :-)
If I enter 200 tons i get the error Message twice
Until I enter more than 500 tons ther are no error Messages anymore.
So how do I remove the double Error Message?
I think the Problem is in my MessageProcessor.constructor
There I am having 2 Entries withc different ID´s . I think I can solve the problem by remove the ID but i dont know how .
enter image description here
I'm actually trying to get some data from a website in CasperJs. The datas are stocked in a table.
I'm trying to get a proper JSON file after the scrap. A json with :
- name of the company,
- mail,
- website
- description of activity.
Until now I've been able to open the page and get the data but not precisely (mail and website are on the same ). So I've found how to select precisely each element I want.
But in this case I don't get all table information's, only first row...
I would know if somebody could help me, telling me where to look or how to make loop in my case ? Assume I'm not a professional developper, I'm training myself.
Here my code :
var casper = require('casper').create();
var url = 'http://www.rent2016.fr/pages/exposants';
var fs = require('fs');
var length;
casper.start(url);
casper.then(function() {
this.waitForSelector('table#myTable');
});
casper.then(function(){
var info = this.evaluate(function(){
var table_rows = document.querySelectorAll("tr"); //or better selector
return Array.prototype.map.call(table_rows, function(tr){
return {
nom : document.querySelector(".td-width h3").textContent,
description: document.querySelector(".td-width p").textContent,
mail : document.querySelector("td span a").textContent,
site : document.querySelector('td span a[href^="http"]').textContent,
};
});
});
fs.write('test_rent_stringify.json', JSON.stringify(info), 'w');
this.echo(JSON.stringify(info, undefined, 4));
});
casper.run(function() {
});
Here, we don't have loop : JSON repeat the first row information's. To get every rows informations you have to replace
nom : document.querySelector(".td-width h3").textContent,
by
nom : tr.children[1].textContent,
but in this case you can't precisely target the H3, the links... you get all the information. So actually I can :
loop through the rows and get informations, but they unusable
have only the first row informations but with good presentation
Thanks in advance !
In order to take information inside every element, you have to use tr.querySelector rather than document.querySelector.
The following loop works fine with the page:
var table_rows = document.querySelectorAll("tbody tr"); //or better selector
return Array.prototype.map.call(table_rows, function(tr) {
return {
nom: tr.querySelector(".td-width h3").textContent,
description: tr.querySelector(".td-width p").textContent,
mail: tr.querySelector('td span a[href^="mailto"]').textContent,
site: tr.querySelector('td span a:not([href^="mailto"])').textContent
};
});
I can succesfully logged in a website and then fill a form and get the results.
Now im trying to do this for anyone who uses my app. The problem is that the form I have to fill has a field name that changes to the number of user.
like this:
casper.thenOpen('http://www.foo.com/index.html', function() {
this.fill('form[action="/cgi-bin/login.cgi"]', { login: user,password:pass }, true);
this.click('input[type="submit"][name="enter"]');
this.wait(5000,function(){
this.capture('eff_ss2.png');
});
});
Everything is fine untill here (I read the login and pass with casper.cli.raw.get();
and then I do this:
this.fill('form[action="../foo.cgi"]', {
'from_city': ori,
'to_city': dest,
'plan_03231': 'whatev',
'aspp_03231': 'whatev'
}, true);
The 03231 will change according to the user who logged in. How can I do this dynamically? I already tried to make:
var plan = 'plan_0'+user;
var obj{}
obj[plan] = 'whatev'
this.fill('form[action="../foo.cgi"]', {
'from_city': ori,
'to_city': dest,
obj,
'aspp_03231': 'whatev'
}, true);
but is not working. Can somebody help me?
In your last snippet you have the id of the user in the user variable, but put an object into an object item place. This is not valid JavaScript. Since the object key is a composite, you need to set it using obj[''+id] = ''; syntax:
var obj = {
'from_city': ori,
'to_city': dest
};
obj['plan_0'+user] = 'whatev';
obj['aspp_0'+user] = 'whatev';
this.fill('form[action="../foo.cgi"]', obj, true);
An easier method where you don't need the explicit user id is simply selecting the form fields based on the beginning of the name attribute using the ^= attribute matcher and casper.fillSelectors:
this.fillSelectors('form[action="../foo.cgi"]', {
'*[name="from_city"]': ori,
'*[name="to_city"]': dest,
'*[name^="plan_0"]': 'whatev'
'*[name^="aspp_0"]': 'whatev'
}, true);
I have found the #Olegs answer for FORM based select2 integration to jQgid, but I need help to get it to work in inline mode,, this jsfiddle is my attempt to get my problem online somehow I'm new with fiddle so please be patient :)
http://jsfiddle.net/mkdizajn/Qaa7L/58/
function(){ ... } // empty fn, take a look on jsfiddle
On this fiddle I can't make it to work to simulate the issue I have in my local network but the problem with this select2 component is that when I update some record(via local or ajax), the grid does not pick up my change and it sends null for values where select2 fields are!
I'm sorry that I can't make jsfiddle to work like on my PC :(
Thanks for any help you can think off that may be the issue here..
P.S. one veeeery strange thing is that when I console.log( select2-fields ), before, and after the value is picked up correctly but I suspect that the grid loose that value somewhere in between .. and send null values to server..
I'm posting this in a good will that I think will help anyone if come to close incounter with similar problem like me..
I'll try to bullet this problem out step by step..
first, on my server side I generate one html tag somewhere near grid table that holds info what columns, fields are lookup type.. like this:
<div id="hold_lookup_<?=$unique_id?>" style="display: none"><?php echo $lokki; ?></div>
that gives me output like this:
<div id="hold_lookup_table1" style="display: none">col1+++col2+++col3</div>
define onselectrow event somewhere
$onSelectRow = "function(){
f = $(this).attr('id'); // grid name
try{
n = $('#hold_lookup_' + f).text().split('+++');
}catch(e){
console.log(e)
}
rez = ''; // results
temp = 'textarea[name='; // template
$.each(n, function(index, item){
rez += temp + item + '],'
});
rez = rez.slice(0,-1); // rezemo zadnji zarez
$( rez ).select2({ .. define my ajax, my init etc.. });
}";
$dg->add_event("jqGridInlineEditRow", $onSelectRow);
last but very tricky part is here.. I destroy select2 columns before sending to database in jqgrid.src file where function for SAVE inline method is.. like this
if (o.save) {
$($t).jqGrid('navButtonAdd', elem, {
caption: o.savetext || '',
title: o.savetitle || 'Save row',
buttonicon: o.saveicon,
position: "first",
id: $t.p.id + "_ilsave",
onClickButton: function() {
var sr = $t.p.savedRow[0].id;
rez = rez.split(',');
rez1 = '';
$.each(rez, function(index, item) {
rez1 += item + ','
})
rez1 = rez1.slice(0, -1);
rez1 = rez1.split(',');
$.each(rez1, function(index, item) {
$(item).select2('destroy');
});
you can see that I inserted the code onclickbutton event via same 'rez' variable that was defined in my php file where I created grid..
That's it, I hope that helped someone, event if not in this particular problem, but with methods that was used here :)
cheers, kreso
I have a select box with a list of books. The user can select a book and hit the submit button to view the chapters on a separate page.
However, when the user changes the select box, I would like a partial page refresh to display the past notes the user entered on the book, and allow the user to write a new note for that book. I do not want the review and creation of notes for a particular book done on the next page with the chapters, as it will clutter it up.
I'm using Python/Bottle on the backend and its SimpleTemplate engine for the front end.
Currently, when the select box is changed, an ajax call receives a Json string containing the book information and all the notes. This json string is then converted into a json object via jQuery.parseJson().
What I would like to be able to do is then loop over the notes and render a table with several cells and rows.
Would I have to do this in jQuery/js (instead of bottle/template framework) ? I assume so as I only want a partial refresh, not a full one.
I'm looking for a piece of code which can render a table with variable numbers of rows via jQuery/js from a json object that was retrieved with ajax.
<head>
<title>Book Notes Application - Subjects</title>
<script src="http://code.jquery.com/jquery-latest.min.js"
type="text/javascript"></script>
<script>
$(document).ready(function(){
$('#subject_id').change(function(){
var subject_id = $(this).val();
$.ajax({
url : "subject_ajax?subject_id=" + subject_id,
success : function(data) {
alert(data)
json = jQuery.parseJSON(data);
},
error : function() {
alert("Error");
}
});
})
})
</script>
</head>
<body>
<!-- CHOOSE SUBJECT -->
<FORM action="/books" id="choose_subject" name="choose_subject" method="POST">
Choose a Subject:
<select name="subject_id" id="subject_id">
% for subject in subjects:
<option value="{{subject.id}}">{{subject.name}}</option>
% end
</select><input type="submit" name="sub" value="Choose Subject"/>
<BR />
</FORM>
This greatly depends on how your JSON and HTML are formatted. But with a table somewhere like:
<table id="books">
<tr>
<th>Chapter</th>
<th>Summary</th>
</tr>
</table>
You could do something like:
$(function(){
$('#choose_subject').submit(function () {
var subject_id = $(this).val();
$.getJSON("subject_ajax?subject_id=" + subject_id, function(data) {
console.log(data);
$.each(data.chapters, function (index, chapter) {
$('#books').append('<tr><td>' + chapter.title + '</td><td>' + chapter.summary + '</td></tr>');
})
});
return false;
})
})
This supposes JSON like:
{
"notes": [
"Note 1",
"Note 2"
],
"chapters": [
{
"title": "First chapter",
"summary": "Some content"
},
{
"title": "Second chapter",
"summary": "More content"
}
]
}
Other notes:
If you use HTML 4 or earlier, keep all your tags in upper case. If you're using XHTML or HTML5, keep all your tags in lower case.
You don't need $(document).ready(function () {...}), with recent versions of jQuery $(function () {...} ) works the same and it's easier to read.
You can use $.get instead of $.json if you're only using the success state (as you are here). And if you're confident that the data you'll get is valid JSON, you can use getJSON instead of get. It will parse the JSON for you deliver it to you as a JavaScript object automatically.
It's usually more convenient to use console.log rather than alert when you're testing. Actually, it's usually a bad idea in general to ever use alert.
I'm not familiar with Python/Bottle or its SimpleTemplate engine, but you could consider generating the html for the table on the server side and returning it in the ajax response, rather than returning JSON.
var subject_id = $(this).val();
$.ajax('subject_ajax', {
type: 'get',
data: { subject_id: subject_id },
dataType: 'html',
success : function(html) {
// Insert the html into the page here using ".html(html)"
// or a similar method.
},
error: function() {
alert("Error");
}
});
When calling .ajax():
The "type" setting defaults to "get", but I prefer to explicitly set it.
Use the "data" setting for the ajax call to specify the URL parameter.
Always specify the "dataType" setting.
I also recommend you perform the ajax call in an on-submit handler for the form, and add an on-change handler for the select that submits the form.
$(document).ready(function(){
$('#subject_id').change(function() {
$(this.form).submit();
});
$('#choose_subject').submit(function(event) {
event.preventDefault();
var subject_id = $('#subject_id').val();
if (subject_id) {
$.ajax(...);
}
});
});
This way your submit button should work in case it is clicked.
There are a few things you need to look at:
1) Is your SimpleTemplate library included?
2) Have you compiled your template via compileTemplate()?
Once you know your library is included (check console for errors), pass your data returned to your success handler method, compile your template, that update whichever element you are trying to update.
I'm not sure that you want to update the same element that you're defining your template in.
$(document).ready(function(){
$('#subject_id').change(function(){
var subject_id = $(this).val();
$.ajax({
url : "subject_ajax?subject_id=" + subject_id,
success : function(data) {
var template_data = JSON.parse(data);
var template = $('#subject_id').toString(); // reference to your template
var precompiledTemplate = compileTemplate(template);
var result = precompiledTemplate(template_data);
$('#subject_id').append(result);
},
error : function() {
alert("Error");
}
});
})
})
You might also try moving your template out of the element you're trying to update like this:
<script type="text/template" id="subject-select-template">
% for subject in subjects:
<option value="{{subject.id}}">{{subject.name}}</option>
% end
</script>
Then just create a blank select element like so:
<select id="select_id"></select>
Update references. Anyway, hope this is helpful. It should work but I can't test without your specific code ;)
Also, check out this demo example if you haven't yet:
https://rawgithub.com/snoguchi/simple-template.js/master/test/test.html