httr/RCurl: Login to sitecore [r] - javascript

Trying to login into a sitecore site with R to fetch html tables.
Part one, login did succeed after adding the following to the code.
EVENTVALIDATION <- as.character(sub('.*id="__EVENTVALIDATION" value="([0-9a-zA-Z+/=]*).*', '\\1', html))
Using the code example from: How to login and then download a file from aspx web pages with R
Did try other possibilities but this looks most promising)
Is it just me having problems 'deciphering' the tags structure, or are there more grave errors in this approach
library(RCurl)
Set some handy curl options:
username = 'YourUser'
password = "YourPass"
url="http://formular.sinusenergi.dk/sitecore/login"
url2="http://formular.sinusenergi.dk/viewforms.aspx"
curl = getCurlHandle()
curlSetOpt(cookiejar = 'cookies.txt', followlocation = TRUE, autoreferer = TRUE, curl = curl)
##Load the page for the first time to capture VIEWSTATE:
html <- getURL(url, curl = curl)
## Extract VIEWSTATE with a regular expression or any other tool:
viewstate <- as.character(sub('.*id="__VIEWSTATE" value="([0-9a-zA-Z+/=]*).*', '\\1', html))
EVENTVALIDATION <- as.character(sub('.*id="__EVENTVALIDATION" value="([0-9a-zA-Z+/=]*).*', '\\1', html))
Set the parameters as your username, password, VIEWSTATE, EVENTVALIDATION :
params <- list(
'Login$UserName' = username,
'Login$Password' = password,
'Login$Login' = 'Login',
'__VIEWSTATE' = viewstate,
**"__EVENTVALIDATION" = EVENTVALIDATION**
)
Log in at last:
html = postForm(url, .params = params, curl = curl)
So now I do get logged in, but grepl('Logout', html) still returns false.
So now I can get to URL2 but haven't figure out how to 'trigger. the product selector, see code below.
This dos not work:
params2 <- list(
'ddlProducts' = '83d16692-63e0-4e9c-9720-0108cfd4fd05',
'__VIEWSTATE' = viewstate,
"__EVENTVALIDATION" = EVENTVALIDATION
)
##Verify if you are logged in:
html = postForm(url2, .params = params2, curl = curl)
Returns the 'product selector code, but does not trigger, the same.
Thanks
Excerpt from site code:
<!-- language: lang-html -->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title>
</title></head>
<body>
<form method="post" action="/viewforms.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTQxMzE0MzQyMw8WAh4TVmFsaWRhdGVSZXF1ZXN0TW9kZQIBFgICAxBkZBYEAgEPZBYEAgEPEA8WBh4ORGF0YVZhbHVlRmllbGQFA0tleR4NRGF0YVRleHRGaWVsZAUFVmFsdWUeC18hRGF0YUJvdW5kZ2QQFQgMVmFsZyBwcm9kdWt0ClNQQVIgc3Ryb20WRXJodmVydiBWQVJJQUJFTCBzdHJvbQpTUE9UIHN0cm9tEkVyaHZlcnYgU1BPVCBzdHJvbQ5WQVJJQUJFTCBzdHJvbQpGQVNUIHN0cm9tEkVyaHZlcnYgRkFTVCBzdHJvbRUIAi0xJDgzZDE2NjkyLTYzZTAtNGU5Yy05NzIwLTAxMDhjZmQ0ZmQwNSRkYTdhZmNhOS1iZWVmLTQ3NDgtODhhNC0wNWQ1MTQ4NDBmZGMkYjg0ZjFiNjMtMDVkZi00MjFjLWFlNGQtMTdjYWZkY2ZmZjc0JGNhNmYxYmQwLTBlYjEtNDExOC1hYmY4LTdlZmFmYTRmNTI2YyQ2NTY2YzgyZS1mNjcyLTQwZGYtOGJkYS1hYjAzOTI3YzdiOGQkN2E3YTVmY2ItMDFkNi00Mzg1LTgwZDUtZjY4MTY5ZmI2NGJmJGY5N2FmNWI1LTAxZDYtNGU4NC1iZjUwLWZhZDU1ZTJmZDU4NxQrAwhnZ2dnZ2dnZxYBZmQCAw88KwARAQwUKwAAZAIDDw8WAh4HVmlzaWJsZWhkZBgBBQ5ndlByb2R1Y3RzRm9ybQ9nZApFHGp6DkfeGiiy/DYgq3lHp9Aq7IMgedEE3Ce3QI0m" />
</div>
<div class="aspNetHidden">
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEdAAl0n//hvd...A==" />
</div>
<div>
<div id="pForm">
<select name="ddlProducts" id="ddlProducts">
<option selected="selected" value="-1">Valg produkt</option>
<option value="83d16692-63e0-4e9c-9720-0108cfd4fd05">SPAR strom</option>
<option value="da7afca9-beef-4748-88a4-05d514840fdc">Erhverv VARIABEL strom</option>
<option value="b84f1b63-05df-421c-ae4d-17cafdcfff74">SPOT strom</option>
<option value="ca6f1bd0-0eb1-4118-abf8-7efafa4f526c">Erhverv SPOT strom</option>
<option value="6566c82e-f672-40df-8bda-ab03927c7b8d">VARIABEL strom</option>
<option value="7a7a5fcb-01d6-4385-80d5-f68169fb64bf">FAST strom</option>
<option value="f97af5b5-01d6-4e84-bf50-fad55e2fd587">Erhverv FAST strom</option>
</select>
<div>
</div>
<span id="lbResult"></span>
</div>
</div>
</form>
</body>
</html>
Solved the last part:
Needed to include: __EVENTTARGET' and the choice for the eventarget variable.
Så the final 'params' list have the following structure.
'__VIEWSTATE' = viewstate,
'__EVENTVALIDATION' = EVENTVALIDATION,
'__EVENTTARGET' = "ddlProducts",
'ddlProducts' = x[1]

Automating the admin screens of the CMS is not an easy task, and unless it is something but the very rudimentary it is likely to break in the future as content changes.
You should look into the Sitecore Item Web API instead, which will allow you to access and manipulate Sitecore conent items via a REST API returning data in JSON format. You can also apply security to restrict access and the calls can be made either from client side or from server side C# code.
Sitecore Item Web API Client Library
Content-As-A-Service and the Sitecore Item Web API
SitecoreJunkie: Sitecore Item Web API
There is also a great walkthrough by Mike Reynolds in this Youtube video.
Example usage:
var query = new SitecoreExpressionQuery(SitecoreQueryType.Read);
query.Query = "/sitecore/content/Home/*";
var credentials = new SitecoreCredentials();
credentials.UserName = "extranet\\foo";
credentials.Password = "bar";
credentials.EncryptHeaders = true;
var context = new AuthenticatedSitecoreDataContext("host", credentials);
ISitecoreWebResponse response = context.GetResponse(query);
if (response.StatusCode == HttpStatusCode.OK)
{
foreach (WebApiItem item in response.Result.Items)
{
// the Key property of the KeyValuePair holds the field id
foreach (KeyValuePair<string, WebApiField> field in item.Fields)
{
Console.WriteLine("fieldid: " + field.Key);
Console.WriteLine("fieldname: " + field.Value.Name);
Console.WriteLine("fieldtype: " + field.Value.Type);
Console.WriteLine("fieldvalue: " + field.Value.Value);
}
}
}

Related

Django Rest Framework - get related FK object for use in template; POST not working now?

I've got a form up and working with a Vue frontend and DRF backend. It's a form for adding (creating) a new model - and has a dropdown of the related models that are FK to the model being created.
I need to access attributes of the selected FK item.
My serializers look like this:
class SubdomainSerializer(serializers.ModelSerializer):
class Meta:
model = Subdomain
fields = [
"id",
"domain",
"short_description",
"long_description",
"character_code",
]
# def get_absolute_url(self, obj):
# return obj.get_absolute_url()
class EvidenceSerializer(serializers.ModelSerializer):
created_by = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
updated_by = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
absolute_url = serializers.SerializerMethodField()
created_by_name = serializers.SerializerMethodField()
updated_by_name = serializers.SerializerMethodField()
class Meta:
model = Evidence
fields = "__all__"
The form is to create a new 'Evidence' item, and the 'Subdomain' is a dropdown on the form that contains all related subdomains.
The models look like this:
class Subdomain(CreateUpdateMixin):
domain = models.ForeignKey(Domain, on_delete=models.PROTECT)
short_description = models.CharField(max_length=100)
long_description = models.CharField(max_length=250)
character_code = models.CharField(max_length=5)
class Evidence(CreateUpdateMixin, CreateUpdateUserMixin, SoftDeletionModel):
subdomain = models.ForeignKey(Subdomain, on_delete=models.PROTECT)
evaluation = models.ForeignKey(
Evaluation, related_name="evidences", on_delete=models.PROTECT
)
published = models.BooleanField(default=False)
comments = models.CharField(max_length=500)
In my form, I just want to include the short_description of each subdomain when the user chooses it from the dropdown - I may also want to use the long_description as well.
Here is the bit in the form where I render the dropdown:
<div class="form-group col-sm-4">
<label class="" for="subdomain">Subdomain</label>
<select name="subdomain" id="subdomain" class="form-control" v-model="element.subdomain">
<option v-for="choice in subdomains" :value="choice.id" >{{ choice.character_code }}</option>
</select>
</div>
<div class="small" v-if="element.subdomain">
<!-- THIS IS WHERE I WOULD LIKE TO DISPLAY THE SHORT DESCRIPTION FOR THE CHOICE IN THE DROPDOWN -->
{{ choice.short_description }}
</div>
The Form Data looks like this when I POST:
evaluation: 2037
subdomain: 448
comments: Test comments to add to the subdomain
published: true
csrfmiddlewaretoken: 382796ryfuasiodfgyhakljyht37yaisdfaslk3r
Things I have tried - some of which worked for display purposes but seem to have broken the form/POST:
Adding depth=1 to the Meta of the EvidenceSerializer, which worked but made the form no longer submit appropriately. I think it's because it wanted the entire subdomain instead of just the ID? I couldn't get it working - the subdomain always threw an error.
Adding the following to my EvidenceSerializer, which again seemed to break the POST operation, it would cause the subdomain dropdown to throw an error.
subdomain = SubdomainSerializer(read_only=True)
Using both of those methods above the dropdown doesn't recognize the subdomain_id being selected and both end up throwing this error behind the scenes:
Cannot insert the value NULL into column 'subdomain_id', table 'local_app.dbo.myapp_evidence'; column does not allow nulls. INSERT fails.
Any advice on how to proceed would be fantastic.
TLDR; Need to be able to access attributes on a FK relationship for a dropdown using DRF, and be able to submit that item in a form.
Thanks to #bdbd for pointing me in the right direction.
For anyone curious, I resolved it using those links - turns out I needed to change my serializers a little bit:
class SubdomainSerializer(serializers.ModelSerializer):
class Meta:
model = Subdomain
fields = [
"id",
"domain",
"short_description",
"long_description",
"character_code",
]
class EvidenceSerializer(serializers.ModelSerializer):
created_by = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
updated_by = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
absolute_url = serializers.SerializerMethodField()
created_by_name = serializers.SerializerMethodField()
updated_by_name = serializers.SerializerMethodField()
# add the 'subdomain' as read only - but with all the attributes
subdomain = SubdomainSerializer(read_only=True)
# add the 'subdomain_id' as a PrimaryKeyRelatedField with the source being the subdomain
subdomain_id = serializers.PrimaryKeyRelatedField(
queryset=Subdomain.objects.all(), source="subdomain"
)
class Meta:
model = Evidence
fields = "__all__"
Then I updated the HTML a little bit:
<div class="form-group col-sm-4">
<label class="" for="subdomain_id">Subdomain</label>
<select name="subdomain_id" id="subdomain" class="form-control" v-model="element.subdomain">
<option v-for="choice in subdomains" :value="choice" >{{ choice.character_code }}</option>
</select>
</div>
<div class="small" v-if="element.subdomain_id">
{{ element.subdomain.short_description }}
</div>
Then in the ajax call I simply assign the subdomain_id to the subdomain.id
data: {
evaluation : evaluationId,
subdomain_id : vm.element.subdomain.id,
comments : vm.element.comments,
published: vm.element.published,
csrfmiddlewaretoken: vm.sharedStore.state.csrftoken,
},

Google Apps Script - Sheet - Menu Trigger not working

So I am building a mailmerge tool, and it works fine.
Testing the trigger with a hard coded input works fine:
function test(){
sendEmails("TEST MAILMERGE FROM DRAFT")
}
It also works fine if I prompt an input box (relevant section of the code shown).
function sendEmails(subjectLine,sheet=SpreadsheetApp.getActiveSheet()) {
if (!subjectLine) {
subjectLine = Browser.inputBox(
"Mail Merge",
"Type or copy/paste the subject line of the Gmail " +
"draft message you would like to use:",
Browser.Buttons.OK_CANCEL
);
if (subjectLine === "cancel" || subjectLine == "") {
// if no subject line finish up
return;
}
}
However, trying to be smarty pants and have the menu dynamically populated with Subject lines like this:
function onOpen() {
// get the UI for the Spreadsheet
const ui = SpreadsheetApp.getUi();
// add the menu
const menu = ui.createMenu("TEST");
// get the drafts from Gmail
let drafts = GmailApp.getDraftMessages();
// for each draft, create a new menu item
drafts.forEach((draft) => {
// add the drafts to be triggered using the following: addItem(caption: string, functionName: string)
menu
.addItem(
draft.getSubject().toString(),
'sendEmails("' + draft.getSubject().toString() + '")'
)
.addToUi();
});
}
However, this doesn't work. It comes up with the following error:
Error Script function not found: sendEmails(TEST MAILMERGE FROM DRAFT)
Which to me looks like it should work. As the testing trigger that is hardcoded above works.
Am I being daft here? As far as I can see, this should work? But it's not.
When / if I get it working, I will put a check in to account for 'trash' drafts that don't have a subject. Just trying to get it to actually work for now though.
Menu.addItem(caption, functionName)
Parameters:
caption: The label for the menu item, with only the first word capitalized.
functionName: The name of the function to invoke when the user selects the item. You can use functions from included libraries, such as Library.libFunction1.
Menu.addItem() expects a function name without arguments. It doesn't allow to pass arguments in the function.
Workaround:
Based on my understanding, your goal is to have a different menu item that could send emails on each draft messages available in your email account.
You might want to consider using Custom dialogs or Custom sidebars where in you can select your draft message subject that you want to pass as argument when you call your sendEmails() function. You can refer to the sample code as reference.
Sample Code:
(Code.gs)
function onOpen() {
// get the UI for the Spreadsheet
const ui = SpreadsheetApp.getUi();
// add the menu
const menu = ui.createMenu("TEST")
.addItem('Send Email', 'selectDraft')
.addToUi();
}
function selectDraft() {
var html = HtmlService.createHtmlOutputFromFile('draft');
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.showModalDialog(html, 'Select Draft Message');
}
function getDraftSubject(){
// get the drafts from Gmail
let drafts = GmailApp.getDraftMessages();
var subjects = [];
// for each draft, create a new menu item
drafts.forEach((draft) => {
subjects.push(draft.getSubject().toString());
});
Logger.log(subjects);
return subjects;
}
function sendEmails(subjectLine,sheet=SpreadsheetApp.getActiveSheet()) {
Logger.log(subjectLine);
}
(draft.html)
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>Select Draft Subject</h2>
<form id="myForm" onsubmit="handleFormSubmit()">
<div class="form-group">
<label for="subject">Draft Subject</label>
<select class="form-control form-control-sm" id="subject" name="subject" required>
<option value="" selected>Choose...</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<script>
google.script.run.withSuccessHandler(function(subj) {
let select = document.getElementById("subject");
subj.forEach(function(e, i) {
let option = document.createElement("option");
option.value = e;
option.text = e;
select.appendChild(option);
});
}).getDraftSubject();
function handleFormSubmit() {
var value = document.getElementById("subject").value;
google.script.run.sendEmails(value);
document.getElementById("myForm").reset();
}
</script>
</body>
What it does?
Create a custom menu that will show a dialog box based on the draft.html
In draft.html, We used google.script.run.withSuccessHandler(function) to call getDraftSubject() in our server side (apps script) which returned an array of draft message subjects. We then update the form's select class and add options based on each draft message subjects obtained.
When the form was submitted, it will call handleFormSubmit(), we get the selected draft message subject and pass that value using google.script.run.myFunction(...) (any server-side function).
google.script.run.sendEmails(value);
Output:

In Rails, how do I query my database from JavaScript so that I can fill in a textbox?

I have a view that uses the select method in Ruby on Rails to return the following code:
<select class="form-control" name="xyz" id="food_id">
<option value="1">Peach</option>
<option value="2">Apple</option>
<option value="3">Orange</option>
</select>
To pass this information over to the JavaScript file, I am basically using a link_to method in my view, such as the following:
<%= link_to "Import text", "#/", :onclick => "fillTextBox()" %>
In the JS file, how can I basically get the name and description of whatever value is selected in the dropdown? This is as far as I've gotten before I got confused:
function fillTextBox(){
var dropdown = document.getElementById('food_id');
var foodID = dropdown[dropdown.selectedIndex].value;
}
I need to do something like:
var foodName = Food.find(foodID).name;
var foodDescription = Food.find(foodID).description;
Is this possible? The rest of the JS function would basically fill in a textbox using foodName and foodDescription, but I first need to be able to query the database for this information in the first place.
Have you ever tried Gon gem?
In your controller:
def some_method
gon.foods = Food.all
end
Then in your js
gon.foods
In your case, you can attach the complete Food collection in the controller and then find the Food by its id in javascript using somethig like this
var food = gon.foods.filter(function(food) {
return food.id === foodID;
})[0];

Salesforce Lightning Component will not update records via Apex call, freezes

Issue overview: Currently coding a Lightning Component to update records on a custom object. However, every time I trigger the update (via a ui:button), the page freezes and I don't see any errors in the debugger or console. Cannot for the life of me figure out why it won't work.
Context: The component has a number of dropdowns that are populated with records (with the label being the record name). Selecting a new value in the dropdown and hitting "Update" calls the below apex to change a custom field (Status__c = 'Ready') on the new selected item, and then updates the records that occur before it (Status__c = 'Complete). I do all of my security and update checks in another function during init, so you won't see that here (I can post the full code if needed). Just trying to get the update to work.
I would be eternally grateful if someone could show me the error of my ways :]. Always been a huge fan of stackoverflow and looking forward to contributing now that I finally signed up. Thanks for your time everyone!
Apex:
#AuraEnabled
public static void updateMilestones(String deployId,Boolean prodChanged,String newProdMile) {
if( prodChanged == true && newProdMile != null ) {
try {
decimal newProdStepNum;
List <Milestone__c> newReadyProdMile = New List<Milestone__c>();
for(Milestone__c mil1:[SELECT id, Status__c, Step_Order__c FROM Milestone__c
WHERE Deployment__c = :deployID
AND id = :newProdMile LIMIT 1]){
mil1.Status__c = 'Ready';
newProdStepNum = mil1.Step_Order__c;
newReadyProdMile.add(mil1);
}
List <Milestone__c> prodMilesComplete = New List<Milestone__c>();
for(Milestone__c mil2:[SELECT id, Type__C, Status__c FROM Milestone__c
WHERE Deployment__c = :deployID
AND Step_Order__c < :newProdStepNum
AND Type__c = 'Production'
AND Status__c != 'Complete'
AND Status__c != 'Revised']){
mil2.Status__c = 'Complete';
prodMilesComplete.add(mil2);
}
update newReadyProdMile;
update prodMilesComplete;
}
catch (DmlException e) {
throw new AuraHandledException('Sorry, the update did not work this time. Refresh and try again please!');
}
}
}
Javascript:
updateMilestones : function(component, event, helper) {
// update milestones server-side
var action = component.get("c.updateMilestones");
action.setParams({
deployId : component.get("v.recordId"),
newProdMile : component.find("prod-mile-select").get("v.value"),
prodChanged : component.get("v.prodChanged")
});
// Add callback behavior for when response is received
action.setCallback(this, function(response) {
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
// re-run the init function to refresh the data in the component
helper.milesInit(component);
// refresh record detail
$A.get("e.force:refreshView").fire();
// set Update Changed Milestones button back to disabled
component.find("updateButton").set("v.disabled","true");
// show success notification
var toastEvent = $A.get("e.force:showToast");
toastEvent.setParams({
"title": "Success!",
"message": "Milestones have been updated successfully."
});
toastEvent.fire();
}
});
// Send action off to be executed
$A.enqueueAction(action);
}
Component:
<aura:component controller="auraMilestonesController_v2"
implements="force:appHostable,flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction">
<ltng:require scripts="{!$Resource.lodash}" afterScriptsLoaded="{!c.doInit}"/>
<aura:attribute name="recordId" type="String" />
<aura:attribute name="prodMiles" type="Milestone__c[]"/>
<aura:attribute name="prodChanged" type="Boolean" default="false"/>
<!-- FORM -->
<div class="slds-col slds-col--padded slds-p-top--large" id="theform">
<form class="slds-form--stacked">
<!-- UPDATE BUTTON -->
<div class="slds-form-element">
<ui:button aura:id="updateButton" label="Update Changed Milestones" press="{!c.updateMilestones}"
class="slds-button slds-button--brand slds-align--absolute-center" disabled="true"/>
</div>
<hr style="color: #005fb2;background-color: #005fb2;"/>
<!-- PRODUCTION -->
<div aura:id="prod-section">
<div class="slds-form-element">
<label class="slds-form-element__label" for="milestone">Production Milestone</label>
<div class="slds-form-element__control">
<div class="slds-select_container">
<ui:inputSelect aura:id="prod-mile-select" class="slds-select" change="{!c.prodChange}">
<option value="" >--Select One--</option>
<aura:iteration items="{!v.prodMiles}" var="m">
<aura:if isTrue="{!m.Status__c == 'Ready'}">
<option value="{!m.id}" selected="true">{!m.Name} ({!m.User_Name__c})</option>
</aura:if>
<aura:if isTrue="{!m.Status__c == 'Not Ready'}">
<option value="{!m.id}">{!m.Name} ({!m.User_Name__c})</option>
</aura:if>
</aura:iteration>
<option value="completeProdMile" id="completeProdMile">All Production Milestones Complete</option>
</ui:inputSelect>
</div>
</div>
</div>
<div class="slds-form-element">
<label class="slds-form-element__label" for="description">Description</label>
<div class="slds-textarea">
<aura:iteration items="{!v.prodMiles}" var="m">
<aura:if isTrue="{!m.Status__c == 'Ready'}">{!m.Description__c}</aura:if>
<!-- <aura:set attribute="else">All production milestones have been completed.</aura:set> -->
</aura:iteration>
</div>
<hr style="color: #005fb2;background-color: #005fb2;"/>
</div>
</div>
<!-- END PRODUCTION -->
</form>
</div>
<!-- / FORM -->
</aura:component>
I believe the issue is that you have fallen into the all too common trap of naming both a client side and a server side controller method the same (updateMilestones in this case). Try changing the name of either to make them unique and I expect that will get you running.
Yes, there is a bug on this and many of us have been making a very loud noise about getting it fixed!
Also we have a very active Salesforce specific Stack Exchange forum over here https://salesforce.stackexchange.com/ that will get more attention - especially if you tag your posts with lightning-components (e.g. I have my account configured to send me an email alert on every post tagged with lightning-components, locker-service, etc).
That might be javascript causing the error.As it's difficult to solve without knowing the error, I would suggest you debug the error.
Turn on debug mode.
a. From Setup, click Develop > Lightning Components.
b. Select the Enable Debug Mode checkbox.
c. Click Save.
In Chrome Developer Tools, check the "Pause on Caught Exceptions" checkbox in the Sources tab. This can often help finding the source of an issue. Other browsers may have similar options.
Add a debugger statement if you want to step through some code.
debugger;
This is useful when you have a rough idea where the problem might be happening.
debugger
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/debug_intro.htm

Web2py Drop down menu that filters

New to html/javascript/web2py, but I been reading a lot and saw many different ways into sorting and some ways to filtering. However, I haven't found something that is similar to mine.
Right now, I'm creating a website that is similar to Craigslist where you can post items and I'm attempting to make a drop down menu that can filter. For an example, if I click car, it will only show posts that has the keyword Car in the category.
Right now, you can create a post and (IS_IN_SET) will already have the categories there for you. However, this is where I'm getting lost. I'm not sure how to get the keywords from (IS_IN_SET) so I am able to use those words to filter.
This is in db.py
db.define_table('posts',
Field('title', requires=IS_NOT_EMPTY()),
Field('interests'),
Field('category', requires=IS_IN_SET(['Computer', 'Electronics', 'Cars', 'Video Games'])),
In my default/index, I created
<select>
<option value='0'>(Select Category)</option><!--added-->
<option value="Computer">Computer</option>
<option value="Electronics">Electronics</option>
<option value="Cars">Cars</option>
<option value="Video Games">Video Games</option>
</select>
But I don't know where to go from here.
I read that you can use IS_IN_DB to create a drop down filter list.
I tried using, but I'm pretty sure this is wrong....
db.category.requires=IS_IN_DB(db,'category.id','%(Tcategory)s')
Looking for any advice/tips in trying to solve this problem.
Thank you.
Here is a solution that shows the power and simplicity of Web2py. I also added a form to enter new posts. Tested.
IN MODEL (models/posts.py):
post_categories = ['Computer', 'Electronics', 'Cars', 'Video Games']
db.define_table('posts',
Field('title', requires=IS_NOT_EMPTY()),
Field('interests'),
Field('category', requires=IS_IN_SET(post_categories)),
Field('body', "text")
)
IN VIEW (views/default/posts.html):
<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>
{{include 'web2py_ajax.html'}}
<div>
<select id="post-select">
<option value='0'>(Select Category)</option>
{{for item in post_categories:}}
<option value="{{=item}}">{{=item}}</option>
{{pass}}
</select>
</div>
{{=form}}
{{=LOAD('default','posts_load', vars=dict(category=item_selected), target='posts-ajax', ajax=True)}}
<script>
$(document).ready(function() {
// pre-sets the option
$('#post-select option[value="{{=item_selected}}"]').attr('selected', 'selected');
$('#post-select').change(function(event) {
var itemSelected = $(this).val();
var urlOfLoadedComponent = "{{=URL(c='default', f='posts_load')}}";
/* either one of these works but the first is better because it uses ajax */
// refreshes the component with the new subset of records
web2py_component( urlOfLoadedComponent + '?category=' + itemSelected, target='posts-ajax');
//window.location.replace('http:/localhost/posts?category=' + itemSelected);
});
});
</script>
IN VIEW (views/default/posts_load.html):
{{for post in post_rows:}}
<div class="post">
Title: <div class="post_title">{{=post.title}}</div>
Post: <blockquote class="post_body">{{=post.body}}</blockquote>
</div>
{{pass}}
IN CONTROLLER (controllers/default.py):
"""
Usage:
http:/localhost/default/posts
-- or --
http:/localhost/default/posts?category=Computer
"""
def posts():
# if category is specified in the url vars, use it otherwise use 'Computer'
item_selected = request.vars.get('category', 'Computer')
# or you could use the first one in the list:
#item_selected = request.vars.get('category', post_categories[0])
"""
creates the form
processes new posts; posts() function called again on form submit via ajax
the response.js refreshes form after ajax post
"""
form=SQLFORM(db.posts).process()
response.js = "jQuery('#posts-ajax').get(0).reload();"
"""
you don't need to pass "post_categories = post_categories" in the dict
because the view can see the variables defined in the models it runs
"""
return dict(
form = form,
item_selected = item_selected
)
def posts_load():
category = request.vars.get('category', '')
if category:
post_rows = db(db.posts.category==category).select()
else:
post_rows = db(db.posts).select()
return post_rows

Categories