Mixing JavaScript and Scala in a Play template - javascript

I'm not sure how this is done. I could hard code the route I'm trying to use, but I'd like to do this the right way.
I have a dropdown that needs to load a new page on change. Here's basically how I'm trying to do it (I've tried a few variations of this):
#getRoute(value: String) = #{
routes.Accounts.transactions(Long.valueOf(value))
}
<script type="text/javascript">
$(function() {
$("select[name='product']").change(function() {
location.href = #getRoute($(this).val());
}).focus();
$('a.view.summary').attr('href', "#routes.Accounts.index()" + "?selectedAccountKey=" + $('select[name=product]').val());
});
</script>
This produces a identifier expected but 'val' found exception. I also tried surrounding it in quotes, but that causes a [NumberFormatException: For input string: "$(this).val()"]
So how the heck do I insert a value from JavaScript into a Scala function?
Edit
Here's my solution, inspired by the accepted answer. This dropdown is defined in a tag that's made for reuse by different components, and the base URL is different for each component. The way to achieve this was to pass a function that generates a URL based on an account key into the dropdown:
#(accountList: List[models.MemberAccount],
selectedAccountKey: Long,
urlGenerator: (Long) => Html
)
<select name="product">
#for(account <- accountList) {
#if(account.accountKey == selectedAccountKey) {
<option selected="selected" value="#urlGenerator(account.accountKey)">#account.description (#account.startDate)</option>
} else {
<option value="#urlGenerator(account.accountKey)">#account.description (#account.startDate)</option>
}
}
</select>
<script type="text/javascript">
$(function() {
$('select[name=product]').change(function() {
location.href = $(this).val();
});
});
</script>
Then you can define a function like this to pass in:
#transactionsUrl(memberAccountKey: Long) = {
#routes.Accounts.transactions(memberAccountKey)
}
#accountsDropdown(transactionDetails.getMemberAccounts(), transactionDetails.getMemberAccountKey(), transactionsUrl)

You need a way of storing all URLs in the page, e.g.
<option value="#routes.Accounts.transactions(id)">Display</option>
Then onChange, you can:
$("select[name='product']").change(function() {
location.href = $(this).val();
});

Related

case sensitive in select2.js dropdown list

I am currently using select2.js 4.0.3
Scenario
let's say the dropdown list has these options
JavaScript
javascript
Javascript
javaScript
so... when user types java as of now... the list shows all the options (because case doesn't matter as of now)
Example 1
What I want to is... when user types Java only these options should show up
JavaScript
Javascript
Example 2
If user types script ... these options should show up
javascript
Javascript
Example 3
for aS
JavaScript
javaScript
I was looking for the same issue for a long time, but everywhere I found the opposite questions (how to make select2 case-insensitive), so I was very surprised when I found already working solution in the documentation.
function matchCustom(params, data) {
if ($.trim(params.term) === '') {
return data;
}
if (typeof data.text === 'undefined') {
return null;
}
if (data.text.indexOf(params.term) > -1) {
var modifiedData = $.extend({}, data, true);
return modifiedData;
}
return null;
}
$(document).ready(function () {
$("select").select2({
tags: true,
matcher: matchCustom
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet"/>
<select>
<option>javascript</option>
<option>Javascript</option>
<option>JavaScript</option>
<option>javaScript</option>
</select>

use jquery variable in # block razor

I'm strugling with a jquery script inside a cshtml page. For short my question is how to use a var inside a # statement in a cshtml page?
below an example of what I'm trying:
<select id="DefaultText">
<option value="-1">-- select --</option>
#foreach( var d in Model.DefaultTexts )
{
<option value="#d.Id" >#d.Name</option>
}
</select>
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
var text = #Model.DefaultTexts.First( t => t.Id == id );
$('#CustomProductText').val(text);
});
</script>
I can't reach the var id. It's out of scope. I've also tryed it with a for loop and a if statement. But in the if statement I get the same error: out of scope.
The full story is this:
On my page I've a dropdown list. The items to select are short names for default text parts. Based on the id or name, I want to show the default text part in a textbox.
#CustomProductText is my textbox where the content should be placed (code not posted).
I've also tryed it with #: and statement but that did not work.
What am I doing wrong or maybe its not even possible what I'm trying to do.
As an alternative I've added a action to my controller to get the text form there. Below the code:
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
$.post("Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
//$('#CustomProductText').val(text);
});
</script>
controller code:
[HttpPost]
public ActionResult GetDefaultText(int id)
{
using( var context = new MyContext() )
{
var text = context.DefaultText.First( d => d.Id == id ).Text;
return this.Content( text );
}
}
This doesn't work. The action doesn't get hit in debug mode.
regards,
Daniel
The $.post that is not working for you, you should prefix the url with / sign and it will be hit as expected:
$.post("/Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
As for the razor solution, you can't use javascript variables in the razor code as it's not a scripting language. What razor does is simply rendering the strings (be it html or javascript or anything) into the page.
To do what you want you either need to request the server to pass the text to your page or render all the texts you have in the page and then access this rendered content in your javascript.

Zend forms working with ajax/javascript onchange event

I am writing a code to use onchange in my application this is my code so far
.Phtml
<script type="text/javascript">
function submit()
{
$id = intval($_GET['id']);
$satellite = intval($_GET['satellite_id']);
if ($id == 0)
{
echo "Please select a Region";
}
else
{
$query = "select * from satellites where region_id = '".$id."'";
$query = mysql_query($query);
echo "<select name='satellite_id'><option value=''>-- select one --</option>";
while ($row = mysql_fetch_assoc($query))
{
echo "<option value='".$row['satellite_id']."'".($row['satellite_id']==$satellite?" selected":"").">".$row['satellite_name']."</option>";
}
echo "</select>";
//DisplayFormRow ("Satellite", FormDropDownBox ("satellite_id", $SatelliteARY, $Result['satellite_id']));
}
}
</script
//zend code Form
$region_name = new Zend_Form_Element_Select('region_name');
$region_name->setAttribs(array('style' => 'width: 150px;'));
$region_name ->setLabel('Region')
->onchange('this.form.submit();') //tried this code ->onchange('javascript:submit();')
->addMultiOption('--Select One--', '--Select One--');
$mdlRegions = new Model_Regions();
$regions = $mdlRegions->getRegions();
foreach ($regions as $region)
{
$region_name->addMultiOption($region->region_id, $region->region_name, $region->region_short_name);
}
//model
<?php
class Model_Regions extends Zend_Db_Table_Abstract
{
protected $_name = 'regions';
//protected $_name = 'smmedetails';
public function getregion($region_id)
{
$region_id = (int)$region_id;
$row = $this->fetchRow('region_id = ' . $region_id);
if (!$row) {
throw new Exception("Could not find row $region_id");
}
return $row->toArray();
}
public function smmedetails2region($region_name)
{
$data = array(
'region_name'=> $region_name
);
return $this->insert($data);
}
public function getRegions()
{
$select = $this->select();
return $this->fetchAll($select);
}
}
//controller
public function registerAction()
{
$this->view->headScript()->appendFile('/js/ui/jquery.ui.autocomplete.js');
$form = new Form_SmmeDetails();
$this->view->form = $form;
if ($this->getRequest()->isPost()) {
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData)) {
$companyname = $form->getValue('companyname');
$companytradingname = $form->getValue('companytradingname');
$region_name = $form->getValue('region_name');
$satellite_name = $form->getValue('satellite_name');
$city = $form->getValue('city');
$companyaddress = $form->getValue('companyaddress');
$addresscode = $form->getValue('addresscode');
$companypostaladdress = $form->getValue('companypostaladdress');
$postalcode = $form->getValue('postalcode');
$companyphonenumber = $form->getValue('companyphonenumber');
$companyfaxnumber = $form->getValue('companyfaxnumber');
$companycellnumber = $form->getValue('companycellnumber');
$businessemailaddress = $form->getValue('businessemailaddress');
$businesswebsite = $form->getValue('businesswebsite');
$smmedetails = new Application_Model_DbTable_SmmeDetails();
$smmeid = $smmedetails ->smmedetailsSmmeDetails($companyname, $companytradingname, $region_name, $satellite_name, $city, $companyaddress, $addresscode, $companypostaladdress, $postalcode, $companyphonenumber, $companyfaxnumber,
$companycellnumber, $businessemailaddress, $businesswebsite);
// $region = new Application_Model_DbTable_Region();
//$region ->smmedetails2region($formData, $smmedetails->smmeid);
$this->_redirect('/admin/smme/register2/smmeid/'.$smmeid);
} else {
$form->populate($formData);
}
}
}
The code is suppose to view a hidden input select, called satellite when you select a feild option from regions, the satellite should view certain options based on the region selected. In short the region selected should correspond with what the user selected. eg Province is Gauteng, so cites would be, Johannseburg,Pretoria etc. Take note the region and satellite options are called from the database table according to they names and id. The code above keeps giving me and error Message: Method onchange does not exist. Was told not to use onchange method should I be using ajax and can I use javascript and sqlquery in the view or should I call it as an action? If so how? Here is a slight picture example.
Please be of help
Thanks in advance
I'd make a few suggestions to what you have there.
Firstly, for simplicity, I'd not use the onChange function, because I don't see it in the API, plus JavaScript or jQuery written in that way can become difficult to maintain and write properly. It is a lot simpler to instead include an external JavaScript file. By doing this, you can also test and debug the JavaScript separately, as well as reuse it.
Have a look at the excellent document for onChange, and getJson. I've used these and others and they're quite straight-forward. For testing, I recommend QUnit for starters. It makes testing a breeze.
Secondly, if you're using the Zend libraries for Model_Regions and $region_name, then I'd suggest using them instead of the direct mysql calls as well. This will allow you to build a good library which you can continue to expand as needed, plus it makes composing SQL quicker and safer.
For the controller, I'd suggest a RestController with a Restful Route. Here's an excellent tutorial.
I hope this helps you out with the problem. If you need anything more, let me know.
Thanks for emailing me about this.
The way I go about this is as follows:
Firstly I set up the form, and then an action in a controller.
Lets say getmajorgroupAction()
which in that action I would then disable layout, and just get the relevent results based on the id.
Then in the view file, loop through the
so the output from that call would be
<option value="1">1</option>
<option value="2">2</option>
etc
Personally I use jquery now, whereas the post you referenced when you emailed me, I was using another method.
trying to use something like this
jQuery(document).ready(function() {
jQuery("#division").change(function () {var division = jQuery("#division").val();
jQuery("#major_group").load("/module/getmajorgroup/", {division_id: division} );});
});
Hope that makes sense.
Thanks that was useful but i found a way to do it using this formula below, but everytime I click on the first select the while still in the session the second select appears all the time, eg if a person choose the wrong selection and re tried it brings up another field instead of fixing the field. I think its in a countinous loop . heres my script
<script type="text/javascript">
$(document).ready(function() {
$("#region_name").on('change', function () {
ajaxAddField();
}
);
}
);
// Retrieve new element's html from controller
function ajaxAddField()
{
$.ajax(
{
type: "POST",
url: '<?php echo $this->baseURL()?>/admin/ajax/get-cities/city/' + encodeURIComponent($('#region_name').val()),
success: function(newElement) {
// Insert new element before the Add button
//$(this).prev().remove().end().before('#city-label');
$("#city-label").before(newElement);
}
}
);
}
</script>

How to display value of a ViewBag in my view with a JS function?

I want to display the data from a ViewBag in my View with Javascript. Here is my code.
View
<span id='test'></span>
Javascript
function myFunction()
{
$('#test').text('#ViewBag.Test');
}
When myFunction() is called I get the text #ViewBag.Test but not his value. How can I fix this ?
You need to place your JavaScript which takes the #ViewBag.Test value in a page which is interpreted by the Razor view engine. My guess is that this is currently not the case.
If you want to keep your javascript codebase separate from the view (which is entirely reasonable) you can use a global variable:
// in the view:
var testText = '#ViewBag.Test';
// in external js
function myFunction() {
$('#test').text(window.testText);
}
Alternatively, you can use a data-* attribute:
<span id='test' data-text="#ViewBag.Test"></span>
// in external js
function myFunction() {
$('#test').text(function() {
return $(this).data('text');
});
}
What you should be ideally doing is passing the data to the view with a view model. Have a property to store that value you want to pass. For example. Let's think about a page to show the customer details and you want to get the last name in your javascript variable.
Your GET action method
public ActionResult View(int id)
{
var vm=new CustomerViewModel();
vm.LastName="Scott"; // You may read this from any where(DAL/Session etc)
return View(vm);
}
and in your view which is strongly typed to your view model.
#model CustomerViewModel
<div>
Some Html content goes here
</div>
<script type="text/javascript">
var lastName="#Model.LastName";
//Now you can use lastName variable
</script>
EDIT : (As per the question edit) To show the content on some event (ex : some button click), Store the value somewhere initially and then read it as needed and set it wherever you want.
#model CustomerViewModel
<div>
<span id="content"></span>
#Html.HiddenFor(s=>s.LastName)
<input type="button" id="btnShow" value="Show content" />
</div>
<script type="text/javascript">
$(function(){
$("btnShow").click(function(e){
$("#content").html($("#LastName").val());
});
});
</script>
Firstly make sure your ViewBag.Test does got a value, then use a div tag instead of a span and add the following code:
<script type="text/javascript">
$(document).ready(function () {
StartRead();
});
function StartRead() {
document.getElementById("test").innerHTML = '#ViewBag.Test';
}
</script>

Jquery load file and auto select the option after files load

$(document).ready(function(){
$("#country").load("country.php",function(){
//Select the option from DB
$('#country').val("<?PHP echo $country;?>");
//Load state option list
switch($("#country").val()){
case "aus":$("#state").load("aus_state.php",function(){
$('#state').val("<?PHP echo $state;?>");
switch($("#state").val()){
case "aus_ACT":$("#location").load("aus_ACT.php",function(){
$('#location').val("<?PHP echo $location;?>");
...
});break
case "aus_NSW":$("#location").load("aus_NSW.php");break
case "aus_NT":$("#location").load("aus_NT.php");break
case "aus_QLD":$("#location").load("aus_QLD.php");break
case "aus_SA":$("#location").load("aus_SA.php");break
case "aus_TAS":$("#location").load("aus_TAS.php");break
case "aus_VIC":$("#location").load("aus_VIC.php");break
case "aus_WA":$("#location").load("aus_WA.php");break
}
});break
case "eng":$("#state").load("eng_countie.php",function(){
...
});break
case "usa":$("#state").load("us_state.php",function(){
...
});break
}
});
});
I hava a dynamic drop down select option.
[country]->[state]->[location]
I use jquery load the option list. However I need to auto select the option list for user to update. ex. [usa]->[CA]->[LA]
I put a function after the files load, .load(file.php, function(){...})
$('country').val("<?PHP echo data from DB; ?>")
switch state option list depend what value from DB...
Since I have a lots of sub list, this will be very hard to editing. Is any better way to do this?
something like
$("#country").val("<?PHP echo $country;?>").change(function(){
switch($("#country").val()){
case "aus":$("#state").load("aus_state.php");break
case "eng":$("#state").load("eng_countie.php");break
case "usa":$("#state").load("us_state.php");break
}
});
$("#state").val("<?PHP echo $state;?>").change(function(){
switch($("#state").val()){
case "aus_ACT":$("#location").load("aus_ACT.php");break
//...Put all countries's states here
}
});
it's complex, I try my best to explain
You can build maps to identify state page (aus_state.php) from country code (aus), location page from state code, and some necessary deeper mappings. These maps can be constructed either from database or your project structure.
var mapping = {
country_state: {
aus: 'aus_state.php',
eng: 'eng_countie.php',
usa: 'us_state.php'
},
state_location: {
aus_ACT: 'aus_ACT.php',
aus_NSW: 'aus_NSW.php',
...
// it seems that the state code has a country prefix
// so you can merge all countries' locations in a map.
usa_CA: 'usa_CA.php',
}
};
Rather than create all the JS code dynamically, you can write the static part in functions in a separate JS file and only use PHP to generate the changing part. And here only country/state/location changes. You can put the code at the bottom of your HTML page so that it get evaluated and initialized before the $(document).ready handler.
var selection_state = {
country: "<?PHP echo $country;?>",
state: "<?PHP echo $state;?>",
location: "<?PHP echo $location;?>"
};
Rewrite the loading/selecting logic in a separate JS file and load it in the HTML page with <script src="..."></script> tag.
$(function () {
$('#country').load('country.php', function () {
$('#country').val(selection_state.country);
if (! mapping.country_state[selection_state.country])
return;
$('#state').load(mapping.country_state[selection_state.country], function () {
$('#state').val(selection_state.state);
if (! mapping.state_location[selection_state.state])
return;
$('#location').load(mapping.state_location[selection_state.state], function () {
$('#location').val(selection_state.location);
});
});
});
});
It seems that it's unnecessary that the loading of country/state/location to be sequential. You can perform the loading in parallel. (The code bellow has better performance but would have different behavior with the former one when some list failed to load.)
$(function () {
$('#country').load('country.php', function () {
$('#country').val(selection_state.country);
});
if (mapping.country_state[selection_state.country]) {
$('#state').load(mapping.country_state[selection_state.country], function () {
$('#state').val(selection_state.state);
});
}
if (mapping.state_location[selection_state.state]) {
$('#location').load(mapping.state_location[selection_state.state], function () {
$('#location').val(selection_state.location);
});
}
});
PS. For step 1, rather than requesting different page for different country/state, I think it's better to request only two pages to fetch the states/locations and pass the country code / state code as parameters. E.g. request country_state.php?country=aus for all the states in Australia(?). This will simplify the logic at both server and client side, and you will get cleaner project structure. With mod_rewrite, you can bind request of aus_state.php to country_state.php?country=aus, if necessary.

Categories