【问题标题】:JQuery modified Hidden Field Value is empty when posted back to the serverJQuery修改后的隐藏字段值在回发到服务器时为空
【发布时间】:2013-10-09 14:08:32
【问题描述】:

总结:我有一个动态添加到页面的 web 控件。该控件有一个 HiddenField 子控件。我将控件的 ClientID 传递给将值设置为字符串(json 转换为字符串)的 jquery 小部件。当表单回传到服务器时,HiddenField 的值是一个空白字符串。 I 值在 Request.Form[UniqueID] 对象中。该值正在返回到服务器。问题是,当我需要值而不修改大量遗留代码时,我无法访问 Request 对象。

奇怪的是 selectmany 控件是我遇到问题的那个,但它继承自正常工作的 SelectOne。我认为我在 selectmany 类中做错了,因为即使我尝试将一个值推送到 SelectOneHiddenValue 中它也不起作用,但是当 SelectOne 使用它时它可以正常工作。

选择一个:

[ToolboxData("<{0}:SelectOne runat=server></{0}:SelectOne>")]
public class SelectOne : Panel, IControl,ISelectOne
{
    #region structure

    private readonly Panel _selectOneTextboxContainer = new Panel();
    protected readonly TextBox SelectOneTextbox = new TextBox();
    protected readonly HiddenField SelectOneHiddenValue = new HiddenField();
    private readonly Panel _selectOneDropdownImageContainer = new Panel();
    private readonly Image _selectOneDropDownImage = new Image();

    #endregion

    private readonly IList<LookupItem> _selectedItems = new List<LookupItem>();

    #region properties
    public IList<LookupItem> SelectedItems { get { return _selectedItems; } }

    public bool MultiSelect { get; set; }
    public DisplayOption Display { get; set; }
    public string Name { get; set; }

    [DefaultValue(0)]
    public int LookupValueOrgID
    {
        get
        {
            EnsureChildControls();
            return Convert.ToInt32(String.IsNullOrEmpty(SelectOneHiddenValue.Value) ? "0" : SelectOneHiddenValue.Value);
        }

        set
        {
            EnsureChildControls();
            SelectOneHiddenValue.Value = value.ToString();
        }
    }

    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    public string Text
    {
        get
        {
            EnsureChildControls();
            return SelectOneTextbox.Text;
        }

        set
        {
            EnsureChildControls();
            SelectOneTextbox.Text = value;
        }
    }

    /// <summary>
    /// The minimum number of characters a user has to type before the autocompleter activates.
    /// </summary>
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue(1)]
    [Localizable(true)]
    public int MinChars
    {
        get
        {
            int b = (ViewState["MinChars"] == null ? 1 : (int)ViewState["MinChars"]);
            return b;
        }
        set
        {
            ViewState["MinChars"] = value;
        }
    }

    /// <summary>
    /// The number of backend query results to store in cache. If set to 1 (the current result), no caching will happen. Must be >= 1.
    /// </summary>
    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue(10)]
    [Localizable(true)]
    public int CacheLength
    {
        get
        {
            int b = (ViewState["CacheLength"] == null ? 10 : (int)ViewState["CacheLength"]);
            return b;
        }
        set
        {
            ViewState["CacheLength"] = value;
        }
    }

    public string OuterMarkupClientID
    {
        get { return "SelectOne_Container" + ClientID; }
    }

    /// <summary>
    /// If true, target input text is appended to
    /// If false, target input text is replaced
    /// </summary>
    public bool AppendSelectedTextToInput { get; set; }

    public virtual string ContainerClass
    {
        get { return "SelectOneContainer"; }
    }

    #endregion

    #region constructor
    public SelectOne()
    {
        SetCssClasses();
    }

    #endregion
    #region lifecycle overrides

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        AddChildrenToControlCollection();
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        SetupClientEvents();
        ControlHelper.AddRequiredControl(this);

        var resourceName = string.Empty;

        var cs = Page.ClientScript;
        resourceName = "UI.Controls.resources.images.DropDownButton.gif";
        _selectOneDropDownImage.ImageUrl = cs.GetWebResourceUrl(GetType(), resourceName);

        SelectOneTextbox.Attributes.Add("lookupOrgID", LookupOrgID.ToString());
        SelectOneTextbox.Attributes.Add("cacheLength", CacheLength.ToString());
        SelectOneTextbox.Attributes.Add("service", Service);
        SelectOneTextbox.Attributes.Add("selectOneTextboxId", SelectOneTextbox.ClientID);
        SelectOneTextbox.Attributes.Add("selectOneHiddenValueId",SelectOneHiddenValue.ClientID);

    }

    #endregion

    #region private helpers
    private void SetCssClasses()
    {
        this.CssClass = ContainerClass + " AutocompleteContainer";
        _selectOneDropDownImage.CssClass = "SelectOneDropDownImage";
        SelectOneTextbox.CssClass = "SelectOneTextbox QuantifiTextBox";
        _selectOneTextboxContainer.CssClass = "SelectOneTextboxContainer";
        _selectOneDropdownImageContainer.CssClass = "SelectOneDropDownImageContainer";

    }

    private void SetupClientEvents()
    {
        ControlHelper.RegisterAutoCompleteScript(this);
        var resourceName = "UI.Controls.resources.scripts.SelectOne.js";

        string js;
        using (var sr = new StreamReader(GetType().Assembly.GetManifestResourceStream(resourceName)))
        {
            js = sr.ReadToEnd();
            sr.Close();
        }
        ClientScriptProxy.Current.RegisterStartupScript(this, typeof(SelectOne), "SelectOneJS", js, true);

        _selectOneDropDownImage.Attributes.Add("onclick", "SelectOne_ImageClick('" + SelectOneTextbox.ClientID + "');");
    }

    private void AddChildrenToControlCollection()
    {
        _selectOneTextboxContainer.Controls.Add(SelectOneTextbox);
        this.Controls.Add(_selectOneTextboxContainer);

        _selectOneDropdownImageContainer.Controls.Add(_selectOneDropDownImage);
        this.Controls.Add(_selectOneDropdownImageContainer);
        this.Controls.Add(SelectOneHiddenValue);
    }
    #endregion
}

多选:

[ToolboxData("<{0}:SelectMany runat=server></{0}:SelectMany>")]
public class SelectMany : SelectOne, ISelectMany
{
    #region structure

    private readonly Panel _selectedItemsPanel = new Panel();
    private readonly HiddenField _selectManyHiddenField = new HiddenField();

    public override string ContainerClass
    {
        get
        {
            return "SelectManyControlContainer";
        }
    }

    #endregion
    public SelectMany()
    {
        MultiSelect = true;
    }

    #region lifecycle overrides
    protected override void CreateChildControls()
    {
        base.CreateChildControls();


        _selectManyHiddenField.ID = "SelectedItemsHiddenValue";

        this.Controls.Add(_selectedItemsPanel);
        this.Controls.Add(_selectManyHiddenField);

        SelectOneTextbox.Attributes.Add("data-multiselect", MultiSelect.ToString());
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);
        var resourceName = "jquery.SelectedItemCollection.js";

        ClientScriptProxy.Current.RegisterClientScriptInclude(this, Page.ClientScript.GetWebResourceUrl(this.GetType(),resourceName));
        var serializer = new JavaScriptSerializer();
        var startupScript = String.Format("\n$('#{0}').each(function(){{" +
                                          "var selectedPlugin = $(this).SelectedItemCollection(" +
                                          "       {{" +
                                          "          itemData: {1}," +
                                          "          deleteImageUrl: '{2}'," +
                                          "          selectedTextId: '{3}', " +
                                          "          hiddenTextFieldId: '{4}' " +
                                          "       }});}});\n",
            this.ClientID, 
            serializer.Serialize(SelectedItems),
            GetDeleteImageUrl(),
            SelectOneTextbox.ClientID,
            _selectManyHiddenField.ClientID
            );
        ClientScriptProxy.Current.RegisterStartupScript(this,this.GetType(),"SelectedItemsJs_" + this.ClientID,startupScript,true);
    }
    #endregion

    #region public api
    public void BindForm()
    {
        EnsureChildControls();
        this.DataBind();
        var jsonString = _selectManyHiddenField.Value;

        SelectedItems.Clear();
        if (!jsonString.IsNullOrEmpty())
        {
            Json.Decode<IEnumerable<LookupItem>>(jsonString).ForEach(li => SelectedItems.Add(li));    
        }

    }
    #endregion

    private string GetDeleteImageUrl()
    {
        var cs = Page.ClientScript;
        const string resourceName = "UI.Controls.resources.images.close.gif";
        return cs.GetWebResourceUrl(this.GetType(), resourceName);
    }


}

【问题讨论】:

  • 您说 SelectMany 继承自 SelectOne,它工作正常,但您向我们展示了 SelectOneP1S。你是从你认为的类继承的吗?
  • 抱歉,我在复制代码时将 SelectOneP1S 重命名为 SelectOne。其余代码相同。我已经更正了错字。

标签: javascript jquery asp.net webforms


【解决方案1】:

嗯,这很愚蠢。我花了很长时间才找到。基本上,不要滥用 EnsureChildControls() 方法。基类在访问它的一些属性之前调用它。这在 ViewState 恢复之后调用了 RecreateChildControls(),但在我可以检查值之前。

为了纠正这个问题,我在 OnInit 覆盖中为基类和派生类添加了 EnsureChildControls()。这样,我的所有控件都将正确创建,并且 ViewState 在创建后恢复。

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        EnsureChildControls();
    }

【讨论】:

    猜你喜欢
    • 2011-08-12
    • 2011-06-29
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2013-09-03
    • 2011-02-03
    相关资源
    最近更新 更多