03 tháng 6, 2010

Customize SharePoint standard forms with Data View web part

The Data View webpart is encapsulated control for presenting data and uses a SharePoint data source server control to load data items from List or Document Library or multiple List. This web part also allows user to add / edit / remove data entries in data source. SharePoint Designer is used to add (and modify) Data View web part to an existing .aspx page. In this post, I'd like to point out notably things we need to care when working with Data View web part.

Here is the common scenario we may see client's need that the Data View web part is likely a solution: they want to use SharePoint to store invoice data. They have two List :
  • Invoice : store data for an invoice. The possible columns for this list are : Client (could be lookup field but here I use textbox for simple) , Created Date , Payment Status (Completed / Pending / Invalid)
  • Invoice Detail : store items that going with the an invoice. The columns for this list are : Invoice ID (hidden and managed by our code) , Item Name (text for simple) , Price
And they want something that supports them in entering invoice easily. I thought it's not easy to implement a solution that user could be able to enter invoice details when they're creating a new Invoice in the NewForm.aspx of Invoice . So I went for an alternative way : I will customize the DispForm.aspx of Invoice so that Invoice Detail grid shows up below the Invoice item and user can enter invoice details within in DispForm.aspx. Below is some sample pictures I captured from the demo project (download link is in the end of this post)













Before I start, if you have no idea what's Data View web part, kindly read this blog first to get the insight on how to play with Data View webpart: http://www.endusersharepoint.com/2009/05/12/data-view-web-part-the-basics-insert-a-dvwp-on-your-page/

Now I will create a SharePoint-template project for demonstration and use it through this post. From above analysis, List Definition project will be used







After create the project, I organized the folder structure as 12-hive





From the structure, you see that the feature has 2 list definition (and its instances) for Invoice and InvoiceDetail. To start with, I add some fields on two lists and deploy the feature to web. Below is Invoice and Invoice Detail list after installed.









Ok, Now I'll use SharePoint Designer (SPD) to create Data View WebPart in DispForm.aspx of Invoice. First, I open the DispForm.aspx page of Invoice list





Second, I find the default List Form webpart and put the cursor right after that where the new Data View webpart will be added. You can see that two webparts are within the default WebPartZone control in page.





Then I start adding Data View webpart and apply some settings
  • Add InvoiceID column
  • Allow sorting and filtering on header
  • Allow insert/edit/remove




Select Invoice Detail list as source




Select three columns that represent for invoice detail and insert them to list as Multiple Item View





Now we need to do some customization. Open Common Data View Task dialog, click on Edit Columns link to add InvoiceID column which is used to associate invoice detail to a invoice






Click on Data View properties link




Allow sorting / filtering and inserting ...







At this point, the webpart show all invoice detail but we only want it to show invoice detail going with current viewing invoice. To do that, add filtering value on data source. Let create a parameter to represent for ID of Invoice








Name the new parameter: InvoiceID and make it get data from query string




Configure filtering




Only retrieve Invoice Detail that its InvoiceID field is same value as ID parameter in query string








Because the Data View webpart needs to have list id of Invoice Detail in order to retrieve query data as well as perform update to. By default the SPD creates a parameter that contains the current list id Invoice Detail but we should add some code so that the parameter can work on other environment. Let modify the ListID parameter




We will tell the data view webpart to get the list id from our server control (created soon)




Enter the server control ID, this control isn't available in the .aspx page but we'll create soon




Open the DispForm.aspx in Invoice folder in Visual Studio, on the beginning of PlaceHolderMain, add an ASP.NET label control with ID lblInvoiceDetailId

<asp:Content ContentPlaceHolderId="PlaceHolderLeftNavBar" runat="server"/>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">

<asp:Label ID="lblInvoiceDetailId" runat="server" style="display:none;"></asp:Label>

<table cellpadding=0 cellspacing=0 id="onetIDListForm">



We also need to make this page inherit from our class instead of default SharePoint. Go to top of page, modify the Inherits attribute to our code behind (created soon)

<%@ Page language="C#" MasterPageFile="~masterurl/default.master"   
Inherits="DataViewWebPartDemo.Invoice.DispForm,DataViewWebPartDemo,Version=1.0.0.0,Culture=neutral,PublicKeyToken=9f4da00116c38ec5"
meta:webpartpageexpansion="full" meta:progid="SharePoint.WebPartPage.Document" %>



Ok, now we'll create code behind for DispForm.aspx. Add new class in Invoice folder and name it DispForm.aspx.cs








Fill up the file with below code, remember to add Microsoft.SharePoint and System.Web assembly

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace DataViewWebPartDemo.Invoice
{
public class DispForm : Microsoft.SharePoint.WebPartPages.WebPartPage
{
protected global::System.Web.UI.WebControls.Label lblInvoiceDetailId;

public void Page_Init(object sender, EventArgs e)
{
lblInvoiceDetailId.Text = SPContext.Current.Web.Lists["Invoice Detail"].ID.ToString();
}
}
}



In the code, we assign the current Id of list named Invoice Detail to control so that the data view webpart then use it to retrieve data

You need to modify the web.config (adding SafeControl) after deploying the feature and assembly in order the DispForm.aspx can be run in SharePoint


Save all changes before going on





SPD will generate XSL definition based on what we've done on the UI, so we need to pack those definition to the feature. This can be done by using webpart exporting option on SharePoint UI. Let just create a test item on Invoice list and view it in display view





Now we're going to export what we have done so far on data view webpart






Temporarily save Invoice_Detail.webpart to Desktop




Open schema.xml file of Invoice list in feature





Modify the Form (Type="DisplayForm") element as below
<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main">
<WebParts>
<AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
<![CDATA[

<!-- Exported webpart definition goes here -->

]]>
</AllUsersWebPart>
</WebParts>
</Form>
<Form Type="EditForm" Url="EditForm.aspx" WebPartZoneID="Main"/>
<Form Type="NewForm" Url="NewForm.aspx" WebPartZoneID="Main"/>
</Forms>



Then open the downloaded Invoice_Detail.webpart, copy whole content and put inside CDATA. It looks like below

<Forms>
<Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main">
<WebParts>
<AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
<![CDATA[

<!-- Exported webpart definition goes here -->
<webparts>
<webpart xmlns="http://schemas.microsoft.com/WebPart/v3">
<metadata>
<type name="Microsoft.SharePoint.WebPartPages.DataFormWebPart, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
<importerrormessage>Cannot import this Web Part.</importerrormessage>
</type></metadata>
<data>
<properties>
<property name="MissingAssembly" type="string">Cannot import this Web Part.</property>
<property name="FireInitialRow" type="bool">True</property>
<property name="TitleIconImageUrl" type="string">
............
]]>
</AllUsersWebPart>
</WebParts>
</Form>
<Form Type="EditForm" Url="EditForm.aspx" WebPartZoneID="Main"/>
<Form Type="NewForm" Url="NewForm.aspx" WebPartZoneID="Main"/>
</Forms>



We have finished 80% work so far. Next we have one important thing and it's a little bit problematic: Automate filling the ID of current Invoice item to the Invoice ID field of detail when user enters new detail


This is where SharePoint Designer team comes to help :-). They wrote a blog dealing with problem and it's very helpful :-). Please go and check this blog before going on:
http://blogs.msdn.com/b/sharepoint/archive/2007/06/21/using-javascript-to-manipulate-a-list-form-field.aspx


Now we will employ a little bit JavaScript code to automate filling the value. We will put the javascript code to DispForm.aspx page in Invoice folder in Visual Studio.

<script type="text/javascript">

/////////////////////////////////////////////////////////////
// How they do that: http://blogs.msdn.com/b/sharepoint/archive/2007/06/21/using-javascript-to-manipulate-a-list-form-field.aspx
/////////////////////////////////////////////////////////////

_spBodyOnLoadFunctionNames.push("fillDefaultValues"); // Use JS SharePoint API to register onload event

function fillDefaultValues() {
// Parse the key/value from query string
var qs = location.search.substring(1, location.search.length);
var args = qs.split("&");
var vals = new Object();
for (var i = 0; i < args.length; i++) {
var nameVal = args[i].split("=");
var temp = unescape(nameVal[1]).split('+');
nameVal[1] = temp.join(' ');
vals[nameVal[0]] = nameVal[1];
}

// Assign ID query string to InvoiceID field
setTextFromFieldName("InvoiceID", vals["ID"]);
}

// @fieldName: the field display name
function setTextFromFieldName(fieldName, value) {
// If the webpart isn't in Insert/Edit Mode, the control doesn't exist so using try/catch to prevent error js icon on browser
try {
var theInput = getTagFromIdentifierAndTitle("input", "TextField", fieldName);
if (theInput != null) {
theInput.value = value;
}
}
catch (e) { }
}

function getTagFromIdentifierAndTitle(tagName, identifier, title) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i = 0; i < tags.length; i++) {
var tempString = tags[i].id;
if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {
return tags[i];
}
}
return null;
}</script>



From the JavaScript code, You see that we set the ID in query string to the field called "InvoiceID" (of course we can set the value on lookup field too (as original code showed).


Here is the whole picture of what we've done: when the DispForm.aspx run, the DataView web part look for server control with Id lblInvoiceDetailId and use the GUID to know where the Invoice Detail list. Then when user enters new record for detail, its Invoice ID field is filled automatically by javascript. That's interesting :-).

This is end of the post. Here is download link for the source of sample I presented

23 tháng 5, 2010

How to win friends and influence people

How to Win Friends and Influence People is well-known book for everyone who wants to improve their social skills (Vietnamese version). I read it but sometime it's not easy to remember and follow its ideas. Today I found a mind map picture that summarizes all aspects in the book and I think it would be helpful for other




From Internet

20 tháng 5, 2010

Use Feature to create custom list definition with custom fields and views

Recently I worked a SharePoint project and the client wanted to create some lists with their fields. On a list, they wanted to see items grouped by a particular one of their field. Obviously that the client needed custom list definition with fields and views. At first I thought this project would be not hard but it turned out that there are tricks that I need to know about creating custom list definition. So I'd like to note down those tips here to help out others who may be in trouble like me.

Assume that you looked at How to create custom list definition on MSDN.

1. Custom content type
There is a important note that people usually miss (me too :-) . Let say you create content type ABC which inherits from SharePoint standard Item content type (0x01), you must do two things in your content type definition and list definition
  • In content type ABC definition, remember to include fields which belong to the parent content type (Item) whereas adding custom fields for content type ABC
ContentTypeADefinition.xml

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentType ID="0x01008B7EF87D021E44fbBD83C21212A0B047"
Name="ABC ContentType"
Description="Custom ABC ContentType inherits from Item" >
<FieldRefs>
<!-- IMPORTANT: Remember to include fields that parent content type (Item for this case) uses -->
<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" /> <!-- Title column is required by Item content type so here we include it in definition of ABC content type -->

<!-- Add custom fields here -->
<FieldRef ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" />
</FieldRefs>
</ContentType>
</Elements>
  • Do the same for list definition: include fields required by parent content type
schema.xml

<List xmlns:ows="Microsoft SharePoint" Title="Custom list"
Id="bc53ee2c-46b3-41ea-8deb-e75013c92eed" FolderCreation="FALSE"
Direction="$Resources:Direction;" BaseType="0">
<MetaData>
<Fields>
<!-- IMPORTANT: Add fields required by parent content type (Item) -->
<Field Name="Title" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" DisplayName="$Resources:core,Last_Name;" Sealed="TRUE" SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Title"><!-- _locID@DisplayName="camlid1" _locComment=" " -->
</Field>

<!-- Add custom fields here -->
<Field ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747524}" DisplayName="Item Name"
Name="ItemName" Type="Text" Group="Custom Columns" Required="TRUE"
SourceID="http://schemas.microsoft.com/sharepoint/v3" />
</Fields>

<!-- Other stuffs -->

</Metadata></List>

You can use SharePoint Manager to browse the SharePoint content types and its fields for getting field info easier.


2. Custom view
In order to define custom view, you probably need to know CAML and View schema . But there is another easier way to make it by making use of SharePoint Manager .
First, you create a custom view on desired list on SharePoint UI.



Second, after the view is created, you use SharePoint Manager to get the view definition by copy value of property HtmlSchemaXml in SharePoint Manager to schema.xml to make a new custom view. And there is one more important step





On the <View> element, make sure that those attributes are inserted

<View BaseViewID="2" Type="HTML" WebPartZoneID="Main" DisplayName="Custom view" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/events.png" Url="CustomView.aspx" >

  • BaseViewID : this is an integer, make the attribute value uniquely with other View in schema.xml
  • WebPartZoneID="Main"
  • SetupPath : should be pages\viewpage.aspx so that the viewpage.aspx (this page is available in \\12\TEMPLATE\Pages\) is called when user uses your view

3. Use standard SharePoint forms in custom list

Normally, a custom list definition template created by WSS 3.0 Tools for Visual Studio usually has several files such as NewForm.aspx, DispForm.aspx, AllItems.aspx , ... And all those files are totally same as standard form in SharePoint. So if you don't have any plan to customize them, you can remove them from definition and tell SharePoint to use its standard form instead. The tip here is to add SetupPath attribute on <Form> element. Look at below xml fragment in schema.xml

schema.xml

<Forms>

<!-- I have a customized Display Form so that I keep the file DispForm.aspx in definition and SharePoint will called my customized DispForm.aspx when it renders Display Form -->
<Form Type="DisplayForm" Url="DispForm.aspx" WebPartZoneID="Main" />

<!-- For other forms, I don't change any on them so I use SetupPath attribute to tell SharePoint that calls its standard forms instead -->
<Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
<Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" />
</Forms>

4. Use Lookup field on list instance
You're creating two list definition called AL and BL. In AL you have a lookup field that references to Title field in BL. But the problem is that both AL and BL are custom lists and doesn't exist in site. It means you don't have List ID of BL required for lookup field.

SharePoint support another way to solve this problem by allowing user to put an relative URL on lookup field. How nice it is :-). On our AL and BL, the trick is to provide the correct URL of BL instance in lookup field definition in AL. And the safe way to ensure the correctness of URL is that you use <ListInstance> to create a new list instead of letting user do.

ListInstances.xml

<ListInstance Id="InstanceOfBL" Title="BL List" TemplateType="10010" Url="Lists/BLInstance01">

You can see that I instruct SharePoint to create a new instance of BL template with Lists/BLInstance01 URL. So I will provide this value into lookup list definition in AL and that solves our problem

schema.xml in AL

<Field Type="Lookup" DisplayName="Lookup Field 1" Required="FALSE" List="Lists/BLInstance01" ShowField="Title"
EnableLookup="TRUE" UnlimitedLengthInDocumentLibrary="FALSE" ID="{7FD2A507-E6CB-4516-8C9A-C73E3C747523}"
SourceID="http://schemas.microsoft.com/sharepoint/v3" Name="LookupField1" />


The List attribute is supposed to have a GUID but here we use relative URL (because the list instance haven't existed yet) and SharePoint accepts the url too.

Read more here

5. Create custom List Template as document library

If you're creating a document library as list template. Remember adding two attributes in the definition. Look at below xml fragment

<ListTemplate
Name="CustomDocLib"
DisplayName="Custom Document Library"
BaseType="1"
Type="101"
OnQuickLaunch="TRUE"
SecurityBits="11"
Sequence="1004"
DocumentTemplate="101" />

  • BaseType="1" : this attribute announces SharePoint that you're creating a document library, not a list. BaseType="1" means document library, BaseType="0" means list
  • DocumentTemplate="101" : this attribute makes the New Item menu item appear in New menu in toolbar. If you don't include this, you won't see New Item :-)
6. How to get the SharePoint item (SPItem) that is associated with the webpart editor in NewForm.aspx , EditForm.aspx and DispForm.aspx ?

There is sometime you need to customize editor forms so that you want to retrieve the SPItem which is processed within the form (i.e. to support for your business). E.x: every time user creates new item, you want to update the lookup field in other list that refers to newly created SPItem.

So in this case, we need a customized NewForm.aspx. Create NewForm.aspx (via Windows SharePoint Services 3.0 Tool) for the list definition. Then replace the code behind of NewForm.aspx with yours (it's created soon)

<%@ Page language="C#" MasterPageFile="~masterurl/default.master"
Inherits="MyAssembly.Features.NewCustomForm" %>


Then create new class called NewCustomForm that inherits from Microsoft.SharePoint.WebParPages.WebPartPage class

namespace MyAssembly.Features
{
public class NewCustomForm : WebPartPage
{
// This is the web part declared by default in NewForm.aspx
protected global::Microsoft.SharePoint.WebPartPages.WebPartZone Main;
}
}
}
}


Now we have a customized NewForm.aspx, before go on. Let I show you how we can retrieve the SPItem in editor first. Here the snipet code to get the SP item go with this web part and this code is going to put on our NewCustomForm class.

// By default, this page only has one webpart
// If user has customized it, we stop
if (this.Main.WebParts.Count == 1)
{
var webpartForm = this.Main.WebParts[0] as ListFormWebPart;
if (webpartForm != null)
{
var listItem = webpartForm.ItemContext.Item; // Got the SPItem going with the webpart editor
// do any thing here
// ...
}
}

You can put above code in Page_Load for example to get the item fields, or in Page_Unload to get newly created item (Note, because when a new item is saved, the page is redirected to Source param and it doesn't fire next events such as PreRender, Render so we have to use Unload event, another way is to override Dispose() method)

In short, by using ListFormWebPart.ItemContext.Item property, we can get the associated SPItem within editor and this property is very helpful in many scenarios.


Other tips

16 tháng 5, 2010

C# 4.0

Main reference at: http://msdn.microsoft.com/en-us/vcsharp/ff628440.aspx

The great feature introduced in C# 4.0 is dynamic programming which is also presented in MSDN lately. And some other new features:
  • Named and optional parameters
  • Variance
How named and optional parameter feature works

The C# compiler supports this feature and the runtime have no idea about named and optional parameter at all. The main idea is that the default value of parameter is transformed into attributes which is marked on parameter itself. And when the C# compiler see any invocation using optional or named feature, it will look into the source definition (method, delegate ...) and use info from attributes on optional parameter and then adjust the invocation again.

Below is the sample code using optional feature



And next picture is the disassembled code. It's observed that C# compiler 4.0 generated automatically Optional and DefaultParameterValue attribute on those parameters. And when any invocation to the method DoThing1() occurs, the C# compiler sees these attributes and it knows what value shoud be put to the missing parameter in the invocation.




In nutshell, how to play with covariance and contravariance

Look at below code snipe

Covariance
IList<Stream> streams = new List<FileStream>();


Contravariance
IList<FileStream> streams = new List<Stream>();

And the reason why this magic can happen are available on net. But I can understand it in this way: two these features allow us to cast generic interface or method to relative its subclass or superclass.

And dynamic

dynamic gives C# wings to make it more stronger. Before NET 4.0, C# is statically typed language. Now with Dynamic Language Runtime (a bunch of new API) and C# 4.0 compiler, you can use coding JavaScript style happily in C#.

Here is summary: dynamic is a type. That means I can declare a variable /property / parameter with type dynamic, return a type dynamic in method / property ... I'm even able to use dynamic with some operators like as , is . The distinct feature of dynamic type is that all operators / invocations on dynamic type isn't checked in compiled-time, it's done in runtime. That's all.

Reference for dynamic:

30 tháng 4, 2010

Opening Ceremony of Researching

I create this blog to share and discuss everything that I learn from researching .NET technology at my company (LinkedIn profile). I know this is the time to start new age, pretty interesting work in my career: researching and deployment.

This is the opening post for this remarkable moment. Thank for reading ^_^

Have a nice day

23 tháng 5, 2009

What does job teach us - fresh developer?

When we were in school to learn a job (university, campus, ... ), we usually study only major knowledge for our coming career. It's just main concepts which will help us to obtain missing parts that are necessary in the job but school is unable to teach us. Obviously, the educational environment is always different from real office by many factors (time is most) and everybody agrees with that cause. In school, we could hardly to get the main points of a subject or technology until we are in trouble with real issue that we have to finish within a short time. Personally, I think that's the important thing that we can't experience them at school. Another thing could be that freshers (me, also) generally need to take some time to adapt first new job and train themself to be better - because the fresher's expectation may be getting good income within 1 year (just my thought) :-). But how long the time would be depends on variety of skills they have as well as how professional working environment might be. Sadly, I needed almost one and a half year to see myself in the career, but it's better late than never. The thing that we can't learn real knowledge for job out there is right and we have to accept it. If you want to change right the time in school by your own actions, you will be ahead.

In school, we could draw a perfect picture about up coming job such as : a good mentor to support all kind of question for newbie, a handsome timeframe for assigned tasks, not have to finish 10 items in 1 hour while helping colleagues in their tasks, working with outgoing clients who will let you know any breaking change before 10 days ... However, after several days at first company, we realized what real environment is. Yes, it isn't perfect at all. And next two months, we only focused on doing what we had learned all time in school. The new things didn't appear well as we expected. By this time, we might talk ourself "Hey, why do I hold off learning new stuffs and take a rest in some weeks". Then "some weeks" passed and new urgent task came; and we have to go to new cycle and keep doing things we learned in school. So for. Finally, after your first 1 year, we got nothing from work accept some stuffs we had known already. That could be sad for those who want to earn pretty money in short time ^^.

With our fresher, the point here is how to move skills to next level in a little while. Surely we don't want to use up 3 years to end being junior guy in career. But that doesn't count the case we are in particular situation that forces we have to. Is there any tips to make it ? Yes, a ton of tips are waiting for you to read out there. I just want to list some simple one I learned and used from others, nothing new here at all (you may read somewhere). First and mostly important, pay a lot of attention to foundation skills like time management, effective communication and English (used mainly for reading and asking question ^^). Although these skills won't give us any right away improvement but we eventually achieve great betterment with those. So we should start getting to know them soon. The second item is a bit harder if we were geeky ^^. It's making friend when having chance. The new friend doesn't have to be good as yours in present but it can be someone who has same hobby or goal as you do. The reason is simple : people can't do everything by their own, they need a small help from friends. I admit that may be difficult to do, not all people can talk openly with new friend. But why don't we give it a try ? It's worth doing, I think.

I would like to know reader's view about this, please leave comment if you have any.

02 tháng 4, 2009

Live to work or Live to learn

Last week, I had a small talk with a friend about the attitude to work. She's working at FPT around 2 years. Basically, I think she is good in term of desiring to learn skills/techniques, sharing knowledge. Currently she is in charge of a product for banking to manage exchanging gold. I'm sorry if you're FPTer :-) but I can see FPT style via her project : a product is considered a success if it's released ontime whatever its quality. I'm not going to argue about the quality of her project. That's a long story for managers. I just want to share some thoughts about her view on the job because it's different from me :-).

Her point is all-for-work. That's you should use all your resources (time, mainly) only for producing good software. And after that you will recieve a great reward which could be client's bonus, becoming a leader in another project or moving up :-). The term all-for-work means that your team have to build the product as quick as possible; there is no unit tests, test scripts, spec, .. They are things I had to do or be involved in my team. And as quick as possible could mean you need to work overtime frequently. However, if you have to develop something within a short time, I agree that you will do like this because it's no choice. But the main point in her all-for-work is that she prefers taking time only for product to learning something new that isn't related to work. That's why I call it all-for-work

Mine is opposite : work is only a part of life. Self-improvement is my style. Actually I have learnt a lot from Buu Nguyen. I have completely changed my mind since he interviewed me at FCG Vietnam (CSC Vietnam). I suppose the client is always hard to please so I usually give out the result that almost fits their expectation, no more no less. Then after the task is done, I do self-improvement to make myself better for future. Therefor, things I learn to improve myself aren't quite linked to the project. It can be something else like book reading, a new programming language, another platform for development, blog writing ...

We talked about 30 minutes to protect our oppions. She dislikes my attitude with 2 ideas:
  1. Work can teach us new things and experience you learn from work is better than pure theory.
  2. The pressure from client will let you get the right things to learn new technique instead of looking through it.
That are her points. Hmm, the way I see it that you're going to know ajax if the project requires fast response, you're getting to know unit if you have to use unit test ... That means if project doesn't require any of them, you wouldn't know those stuffs. Does it sound we are inactive to get new knowledge ? Once she asked me "how do you develop your 3-layers in application". It's 3, not 2 or 4 :-).

I'm a open mind guy. Of course I don't tell her off for her way. She has being followed it and she succeeds in her career. I prefer self-improvement in order I can be up for new chance (maybe). All things I wrote in this post just a question : why doesn't she accept my oppion as I did with her ?

Got a lesson. It's hard to change somebody's view :-)