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);
Related
I am using Jade to create a drop down list on a webpage. I want to have this webpage constantly reload(perhaps by a certain time interval) when an item is selected, but I want it to reload with the same selection still selected.
Using something like meta(http-equiv='refresh', content='30') could work for me, but it only reloads the original page every 30 seconds, but not the page with the selected item in the list already selected.
Here is my code:
select(id="foo", multiple="2", size=listStuff.length)
each val in listStuff
option(value=val)=val
script.
$('#foo').on('change', function(context) {
//insert what the selection displays when changed
});
I know I am using jade, but any html experience is welcome, as I can convert between the two languages.
So you need to persist the option in select after refresh. You have couple of options, use session/local storage api or set it in a cookie.
using session storage:
$('#foo').on('change', function(context) {
sessionStorage.setItem("foo", $("#foo").val());
});
and then on page load
$('#foo').val(sessionStorage.getItem("foo"));
If on cookie, you would use something like (jQuery cookie)
$.cookie("foo", $("#foo").val());
Following is an example using the Query string from the URL.
I use the id of the select element as the query string name.
window.addEventListener('load', initPage, false);
var elSelect; // select element
function initPage(sender) {
var selectionValue; // selection from url
// get select, set value, refresh page in 30 seconds
elSelect = document.getElementById('foo');
selectionValue = getQueryString(elSelect.id);
if (selectionValue) {
elSelect.value = selectionValue;
}
setTimeout(refreshPage, 30000);
}
function refreshPage(sender) {
var newUrl; // url to load
// set new query portion, reload
newUrl = "?" + elSelect.id + "=" + elSelect.value;
window.location.href = window.location.href.split('?')[0] + newUrl;
}
// get query string value by name
function getQueryString(sParm) {
var asParms; // query String parameters array
var sLocation; // location URL
var sParmName; // parameter name
var sParmVal; // parameter value
// return false if not found
sParmVal = false;
// split query portion of url, look for sParm name
sLocation = location.search.substring(1, location.search.length);
asParms = sLocation.split("&");
for (var i = 0; i < asParms.length; i++) {
sParmName = asParms[i].substring(0,asParms[i].indexOf("="));
if (sParmName === sParm) {
sParmVal = asParms[i].substring(asParms[i].indexOf("=") + 1)
}
}
return sParmVal;
}
<select id="foo">
<option value="1" selected>fe</option>
<option value="2">fi</option>
<option value="3">fo</option>
</select>
I have a table which had a select field in it which I'd like to save into database if it dosnt exist yet through POST data. If it does exist then I'd like to update the already existing row in the database.
This can be found in the tbody in which i have my tablerow with an ng-repeat to display all data from a json.
<td>
<select id="statusSelect{{anime.id}}" ng-model="statusId" ng-options="animeStatus.id as animeStatus.status for animeStatus in animeStatuses"
ng-change='addUserAnime( "<?php echo Yii::app()->user->id; ?>", anime.id, statusId )'>
</select>
</td>
Next this is my code for what im trying to do in the angular controller:
$scope.addUserAnime = function( userId, animeId, statusId, userAnime )
{
if ( userId == '' ) {
//alert user that he/she needs to log in first
} else {
//loop through my json where i saved from which user which anime is saved with which status
for (var i = 0; i < $scope.usersAnime.length; i++) {
//if there is an already existing entry then i want to update it if not then i want to introduce it into DB with POST
if ($scope.usersAnime[i].anime_id == animeId && $scope.usersAnime[i].user_id == userId) {
$scope.userAnime = $.extend({}, $scope.usersAnime[i]);
$scope.userAnime.status_id = statusId;
$scope.userAnime.date_modified = today;
saveUserAnime();
return;
}
}
$scope.userAnime = {
id: 0,
user_id: userId,
anime_id: animeId,
status_id: statusId,
rating: '',
date_modified: today
};
saveUserAnime();
}
};
Problem is that if i POST a new entry it gets saved in the database, but if i dont reload the page and i change the select again giving it a new option it gets POSTed again instead of using PUT for update.In the end i end up with two entries instead of one. I want to introduce it to database on first select and i want to update it if its changed after. Is that possible. I tryed doing it with $dirty using the table as form but thats a nono.
In the saveUserAnime() function its correctly deffined to use POST if its new entry and use PUT if its an existing one. I have another form for which it works. The problem must be in this current function.
Just put that code where you get the object with the animeStatus and put that in a function and call it directly after that. Now you can call that function when your POST is done, so the new data will be loaded.
Otherwise you could also check through SQL, if that value exists in your table, so you don't need your check in angularjs, that would be easier than this one.
I am trying to update an json object value from a textbox using angular and I'm not sure what the best way to go about it is.
This is the json object...
$scope.productAttributes = {
"CostRequirements":[
{
"OriginPostcode": 'NW1BT',
"BearerSize":100
}
]
}
And when a use types in a text field and clicks a button, I would like to grab that textfield value and pass it into the json object to replace the postcose value (OriginPostcode) I tried to pass in a scope variable but that didnt work.
<input type="text" placeholder="Please enter postcode" class="form-control" ng-model="sitePostcode"/>
And this is the fucntion that is fired when the user clicks a button to submit the json
var loadPrices = function () {
productsServices.getPrices1($scope.productAttributes)
.then(function (res) {
$scope.selectedProductPrices = res.data.Products;
// $scope.selectedProductAddOns = res.data.product_addons;
})
.finally(function () {
$scope.loadingPrices = false;
$scope.loadedPrices = true;
});
};
Could anyone tell me what I need to do to put the user input in the textbox into the json object?
Many thanks
What we don't see is the function that runs the update with the button. It should look something like this
// your HTML button
<button ng-click='updateThingy()'>Update</button>
// your HTML input
<input type="text" ng-model="myObject.sitePostcode"/>
// your controller
$scope.myObject = { // ties to the ng-model, you want to tie to a property of an object rather than just a scope property
sitePostcode : $scope.productAttributes.CostRequirements[0].OriginPostcode // load in post code from productAttributes
};
$scope.updateThingy = function(){
$scope.productAttributes.CostRequirements[0].OriginPostcode = $scope.myObject.sitePostcode;
};
Here is a demo plunker for updating a value on button click, hope it helps out.
http://plnkr.co/edit/8PsVgWbr2hMvgx8xEMR1?p=preview
I guess loadPrices function is inside your controller. Well, then you should have sitePostCode variable available inside your controller and your function. So you just need to inject that value inside $scope.productAttributes.
$scope.productAttributes.sitePostCode = $scope.sitePostCode;
This you need to put it before you make the productsServices.getPrices1 call.
var loadPrices = function() {
$scope.productAttributes.sitePostCode = $scope.sitePostCode;
productsServices.getPrices1($scope.productAttributes)
.then(function(res) {
$scope.selectedProductPrices = res.data.Products;
// $scope.selectedProductAddOns = res.data.product_addons;
})
.finally(function() {
$scope.loadingPrices = false;
$scope.loadedPrices = true;
});
};
Let me know if it worked.
Getting confused, creating a web app where people post notes, I have a field for subject and one for the actual note, when posted these should be saved into two arrays, when posted these should appear almost like a comment, with what you just entered in two fields, which did work but I want people to be able to save their notes, close the browser and return, below is the code that is not working, basically the user should be able to
Allow user to enter in values.
If local storage is available, Take values saved from arrays (which I tried converting to a string then convert back to a array using JSON, which is confusing) and fill the page
$("document").ready( function (){
//Each subjectField.value goes into array
var subjectInputArray = [];
//Each noteField.value goes into array
var noteInputArray = [];
//Color array holds color hex codes as values
var noteColourArray = [];
noteColourArray[0] = "#03CEC2";
noteColourArray[1] = "#ADC607";
noteColourArray[2] = "#ffdd00";
noteColourArray[3] = "#f7941f";
//Variable holds properties for note creation
var noteCreate =
{
noteCreateContainer : $("<article>", { id: "noteCreateContainer" }),
noteForm : $("<form>", { id: "noteFormContainer" }),
subjectField : $("<input>", { type: "text", placeholder: "Title", id: "subject"}),
noteField : $("<input>", { type: "text", placeholder: "Write a Note", id: "noteContent" }),
submitNote : $("<button>", { type: "submit", id: "post", text: "post"}).on( "click", (postNote))
}
//Variable holds properties for a note content (NOT SUBJECT);
var notePost = {}
//--------------------------------------------------------------------------------
//Test if local storage is supported
if( Modernizr.localstorage ) {
//Get current array/list
localStorage.getItem("subjectInputArray")
//Convert string back to array
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
//For each item in subject localStorage array, loop through an fill page with fields containing values
for(var i = 0; i < savedNoteSubjects.length; i++)
{
//Create container for post
//Apply noteCreateContainer's selected background color to the posted note
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($("#noteCreateContainer").css("background-color")));
console.log("local storage: " + [savedNoteSubjects]);
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "subjectFieldPost", type: "text", value: savedNoteSubjects[savedNoteSubjects.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true);
}
} else {
alert("Your browser does not support localStorage, consider upgrading your internet browser");
}
//--------------------------------------------------------------------------------
//Create/Set up fields required for user to input data
noteCreate.noteCreateContainer.prependTo("body");
noteCreate.noteForm.appendTo(noteCreateContainer);
//Loop through noteColourArray and append new button for each item
for (var i = 0, len = noteColourArray.length; i < len; i++) {
noteCreate.noteForm.append($("<button>", {class: "colourSelect", value: noteColourArray[i] }).css("background-color", noteColourArray[i]).click(setBackgroundColour))
}
//Change background colour on click
function setBackgroundColour()
{
$("#noteCreateContainer").css("background-color", noteColourArray[$(this).index()] )
return false;
}
noteCreate.subjectField.appendTo(noteFormContainer);
noteCreate.noteField.appendTo(noteFormContainer);
noteCreate.submitNote.appendTo(noteFormContainer);
//--------------------------------------------------------------------------------BELOW NOTE POST/OUTPUT FROM CREATING NOTE
//FUNCTION - CREATE NEW POST UPON CLICKING POST
function postNote()
{
//Add submitted value of subject field to array
subjectInputArray.push( $("#subject").val() );
//Convert array into string
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
//Add value of note field to array
noteInputArray.push( $("#noteContent").val() );
//Create container for post
$("<article>").appendTo("body").addClass("notePostContainer").css("background-color", ($(noteCreateContainer).css("background-color")) ) //Apply noteCreateContainer's selected background color to the posted note
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
//Pull value from local storage subject array
$("<input>", {class: "subjectFieldPost", type: "text", value: subjectInputArray[subjectInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
//Select last div of class notePostContainer to add input field, instead of adding 1+ input fields on each click to all classes using the same class name
$("<input>", {class: "noteFieldPost", type: "text", value: noteInputArray[noteInputArray.length-1] }).appendTo(".notePostContainer:last-child").prop("disabled", true)
return false;
} //End function
});
An earlier post I made in relation to my idea
button click temporarily changes div background color, not permanently as intended
var subjectInputArray = [];
...
localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray);
You are setting your localStorage["subjectInputArray"] to an empty array every time your page loads.
How could you expect load anything useful from it?
Instead, try put localStorage["subjectInputArray"] = JSON.stringify(subjectInputArray); in postNote(), so every time user input something, you update the localStorage record.
Additionally,
var savedNoteSubjects = JSON.parse(localStorage["subjectInputArray"]);
this line should be inside the test local storage if block. Don't use it until it's confirmed to be available
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'