I have a VisualForce page testPage
<apex:page controller="testController">
{!myString}, {!myString1}, {!myString2}, {!Mystring3}, {!myString}
</apex:page>
And the controller is
public class testController {
public string myString {get;set;}
public string getMyString1()
{
return myString;
}
public string getMyString2()
{
if(myString==null)
myString = 'Method2';
return myString;
}
public void getMystring3()
{
myString = 'Method3';
}
}
When loading the page, it outputs , , Method2, ,.
The methods getMyString2 and getMystring3 both set the property.
Why the myString property is not set here?
I know Salesforce used to reserve the word "test" for test classes. If it's not firing at all, try renaming it. Salesforce may thing they're test classes.
When evaluating the merge expressions in the page:
{!myString}, {!myString1}, {!myString2}, {!Mystring3}, {!myString}
The order of events is:
1., testController get(myString), which is null, since the variable hasn't been initialized
2., testController get(myString1), which is also null since the value being returned is still null
3., testController get(myString2), which sets the variable myString to the value of Method2 and returns that value
4., testController get(Mystring3), which returns sets the variable myString to the value Method3 and returns nothing
5., That's it. Even though {!myString} is written again in the visualforce page, the page doesn't go back to the controller to get the value again, since it already got it once and already knows it's value; assuming (mistakenly in this case) that the value hadn't changed.
If you changed your VF page to:
<apex:page controller="testController">
{!myString1}, {!myString2}, {!Mystring3}, {!myString}
</apex:page>
testController get(myString) would be called after testController get(Mystring3), so the resulting page would display:
, Method2, , Method3
All that being said, a getter shouldn't change the state of a program, and if you are relying on this type of behavior, it will only make your code hard to understand.
Related
Test class :
#isTest
public class PriceName_PriceList_test {
#istest static void PriceName_PriceListMethod(){
PriceName_PriceList priceObj = new PriceName_PriceList();
Product_Line_Item__c prl = New Product_Line_Item__c();
prl = [SELECT Product_Name__r.name, List_Price__c FROM Product_Line_Item__c];
prl.Product_Name__r.name = 'testproduct';
prl.List_Price__c = 123;
insert prl;
PriceObj.getdetails();
}
}
You didn't pass the Id to the class. So with a null the query will return 0. But it's interesting, I'd expect you to at least get coverage for line 6...
Change your code to this and run again
insert prl;
PriceObj.drId = prl.Id;
PriceObj.getdetails();
Or make the function accept an Id parameter and call PriceObj.getdetails(prl.Id), no idea what's your use case
I have a custom ComboBox in WinForms that is supposed to display an enumeration. Basically, I derived from ComboBox and in the constructor, I load the items from the enum.
The problem is that, even though at the end of the process it says the count of items is the same as the enum item count, the visual representation shows as if the same items were added twice. In other words, if my enum had values Value1 and Value2 the ComboBox says it has two values but when dropping down it shows Value1, Value2, Value1, Value2 as if I had added them twice.
public class EnumComboBox : ComboBox
{
public EnumComboBox() : base()
{
foreach (MyEnum p in Enum.GetValues(typeof(MyEnum)) {
base.Items.Add(p);
}
SelectedIndex = 0;
}
}
As you can see in the code, in the constructor the items are added ONCE but they are listed twice. What am I doing wrong here?
Rather than in the Constructor the manner to get it to behave properly was to leave the constructor empty and move the insertion code to the OnCreate method:
protected override void OnCreateControl()
{
if (!DesignMode) {
foreach (MyEnum p in Enum.GetValues(typeof(MyEnum))) {
Items.Add(p);
}
SelectedIndex = 0;
}
}
I understand that List, Array, Object etc. types "copied" by reference. However my natural and ordinary intend is to just have a "copy" of it in this context where I intentionally use ReadOnly instead of Read/Write property. In below sample the ReadOnly 'Extensions' property get change through 'm_extensions' reference change. Regardless, I think this behavior is incorrect and I have to do extra work to prevent ReadOnly properties from being overwritten. Is there any built in keyword to use for 'm_extensions' value protection?
Public Classs A
' more properties and methods here...
Private m_extensions() As String = {"*.abc", "*.def"}
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions
End Get
End Property
End Class
Public Classs B
' more stuff here...
Private Function BuildFilter() As String
Dim l() As String = A.Extensions
Dim s As String = String.Empty
For m As Integer = 0 To l.Length - 1
Select Case l(m).ToLower
Case "*.*" : s = "All Files"
Case "*.abc" : s = "ABC File"
Case "*.def" : s = "DEF File"
Case Else : s = "XYZ File " + m.ToString
End Select
l(m) = String.Format("{1} ({0})|{0}", l(m), s)
Next
Return String.Join("|", l)
End Function
End Class
Readonly modifier means that anything using the property cannot change the reference that you protected this way (e.g. cannot set it to Nothing). It doesn't prevent changing the values in the array returned from that property.
One way around it could be to copy the array inside the property. This will prevent modifications of the original array:
Public ReadOnly Property Extensions() As String()
Get
Return m_extensions.Clone()
End Get
End Property
I am working on ASP.NET MVC4.0.
My string is posting like this from view :-
[{"name":"AddressNumber","value":"1"},{"name":"OrganizationProd","value":""},{"name":"ClientId","value":""},{"name":"ProductId","value":""},{"name":"TaxId1","value":""},{"name":"TaxId2","value":""},{"name":"LaborID","value":"0"}]
And below is my controller's action method for that,which is receiving the input :-
[AllowAnonymous]
[HttpPost]
public ActionResult UpdateProducts(string ModelString){
}
And below is the string which i am getting in action(in ModelString variable):-
[{"name":"AddressNumber","value":"1"},{"name":"OrganizationProd","value":""},{"name":"ClientId","value":""},{"name":"ProductId","value":""},{"name":"TaxId1","value":""},{"name":"TaxId2","value":""},{"name":"LaborID","value":"0"}]
And after that i am deserializing the string like that :-
var sear = new JavaScriptSerializer();
var dictDynamic = sear.Deserialize<dynamic>(ModelString);
And i am getting the dynamic array in dictDynamic variable.And now i want to get the properties by its name not by indexing from dictDynamic object.
Currently i am getting the properties by indexing like this :-
dictDynamic[0]["value"]
dictDynamic[1]["value"]
But i want to parse it by properties name like this :-
dictDynamic["Name"]["value"]
dictDynamic["Description"]["value"]
Can anyone help me out on this ?
You could use ViewModel on server side, not sending model string.
You create ViewModel like this:
class ProductViewModel {
public int AddressNumber { get; set; }
public int ProductId { get; set; }
...
}
Then change your controller method:
[AllowAnonymous]
[HttpPost]
public ActionResult UpdateProducts(ProductViewModel vm){
...
}
And from your View you'll send json object like this:
{
"AddressNumber":"10",
"OrganizationProd":"1",
"ClientId":"1",
"ProductId":"1",
"TaxId1":"23",
"TaxId2":"23",
"LaborID":"10"
}
This will automaticaly bind your values from View to ViewModel on controller, and you can than use ViewModel object in your code, and you then have strongly typed entity.
Instead of this:
dictDynamic["AddressNumber"]
dictDynamic["OrganizationProd"]
now you can write this:
vm.AddressNumber
vm.OrganizationProd
You need to pass a JavaScript object to your function instead of an array. Array is not the correct data structure to use in this case. Objects have keys and values. The keys will be AddressNumber, OrganizationProd, ClientId, ProductId, TaxId1 etc. Their values will be 1, "", "0" etc.
For instance, for your example, this will be your object:
{
"AddressNumber":1,
"OrganizationProd":"",
"ClientId":"",
"ProductId":"",
"TaxId1":"",
"TaxId2":"",
"LaborID":0
}
You deserialize it like you do now:
var s = "{\"AddressNumber\":1, \"OrganizationProd\":\"\", \"ClientId\":\"\", \"ProductId\":\"\", \"TaxId1\":\"\", \"TaxId2\":\"\", \"LaborID\":0}";
var sear = new JavaScriptSerializer();
var dictDynamic = sear.Deserialize<dynamic>(s);
Once you deserialize, you will be able to reference the values like this:
dictDynamic["AddressNumber"]
dictDynamic["OrganizationProd"]
so here is the problem that I have so far. I tried to simplify my code so I can attempt to figure this out, but I have had absolutely no luck. I have a viewstack that contains 1 dropdown per stack. They share the same data provider. What I want to do is to select the item contents from the first one. Once I do that, when I click a button to the next stack I have a function that searches from index 0 to the dataprovider length and if the item from the first stack matches the second one, I want to have the second dropdown pick that item up and display it. I have it matching, and I try to select it, but when I run the application it shows up like nothing is selected. Here is what I have:
edit: I got it to work for a simple example, but when I attempt to use it in my more complicated example, on that button click it for some reason resets the value of selectedIndex to -1. How do I prevent this from happening? This is working code for the simple example
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" applicationComplete="popList()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.controls.Alert;
[Bindable]
private var myList : ArrayCollection;
[Bindable]
private var selectedItem : String;
[Bindable]
private var index : int;
[Bindable]
private var ind : int;
private function popList() : void {
myList = new ArrayCollection();
stack.initialize();
myList.addItem("1");
myList.addItem("2");
myList.addItem("3");
myList.addItem("4");
myList.addItem("5");
myList.addItem("6");
first.initialize();
second.initialize();
}
private function goNext() : void {
selectedItem = first.selectedItem;
stack.selectedChild = stackb;
for(index = 0; index < myList.length; index++){
var itemNow : String = myList[index].toString();
if(selectedItem == myList[index].toString()){
ind = index;
}
}
}
]]>
</fx:Script>
<mx:ViewStack id="stack" width="862" height="500">
<s:NavigatorContent id="stacka">
<s:DropDownList x="317" y="174" id="first" dataProvider="{myList}"></s:DropDownList>
<s:Button id="next" x="335" y="263" label="Next" click="goNext()"/>
</s:NavigatorContent>
<s:NavigatorContent id="stackb">
<s:DropDownList x="317" y="174" id="second" dataProvider="{myList}" selectedIndex="{ind}"></s:DropDownList>
</s:NavigatorContent>
</mx:ViewStack>
</s:Application>
I didn't try to run the code, but I have a bunch of observations:
First, don't use the same dataProvider for two separate DropDownLists. It causes weird issues. It makes no sense, I have no idea why; but it does. You could dupe the dataProvider by creating a second collection using the same source. Something like this:
-
second.dataProvider = new ArrayCollection(myList.source);
Second, you shouldn't have to manually call the initialize method on either of the DropDownLists. That is highly unusual. The initialize event is fired as part of the creation process; and I assume the initialization method is part of the default event handler. But, firing that event is not the same as having the component go through it's Lifecycle process.
A ViewStack doesn't initialize it's children before the view changes. So, you are probably setting the selectedIndex on the second DropDownList before that DropDownList is initialized, possibly allowing that drop down list to get lost. You can combat this by setting the creationPolicy to all on the ViewStack.
You can probably solve this issue with binding. Something like this.
-
<s:DropDownList x="317" y="174" id="second" dataProvider="{myList}" selectedIndex="{first.selectedIndex}"></s:DropDownList>
Your code to select the next item is comparing an object to a string, so you'll hever the selectedItem.
You could change your loop to something like this:
for(index = 0; index < myList.length; index++){
if(selectedItem == myList[index]){
second.selectedIndex = index;
}
}
But, if you're using the same dataProvider, or a copy of it, why do you even need the loop? Just use the selectedIndex property:
-
second.selectedIndex = first.selectedIndex
Does that help?
Note: StackOverflow makes it real hard to do code formatting inside a list; sorry for not keeping the numbers in my list.