method - حقن المحتوى في أقسام محددة من طريقة عرض جزئية ASP.NET MVC 3 باستخدام محرك عرض الحلاقة




search in mvc (14)

أنا حل هذا الطريق مختلفة تماما (لأنني كنت في عجلة من أمري ولم أكن أريد تطبيق HtmlHelper):

لقد قمت بإخفاء ملفي الشخصي جزئيًا في عبارة if-else كبيرة:

@if ((bool)ViewData["ShouldRenderScripts"] == true){
// Scripts
}else{
// Html
}

بعد ذلك ، اتصلت بـ Partial مرتين مع ملف شخصي مخصص:

@Html.Partial("MyPartialView", Model, 
    new ViewDataDictionary { { "ShouldRenderScripts", false } })

@section scripts{
    @Html.Partial("MyPartialView", Model, 
        new ViewDataDictionary { { "ShouldRenderScripts", true } })
}

لدي هذا القسم محدد في _Layout.cshtml بي

@RenderSection("Scripts", false)

يمكنني استخدامه بسهولة من العرض:

@section Scripts { 
    @*Stuff comes here*@
}

ما أعاني منه هو كيفية الحصول على بعض المحتوى المحقون داخل هذا القسم من عرض جزئي.

لنفترض أن هذه صفحة المشاهدة الخاصة بي:

@section Scripts { 

    <script>
        //code comes here
    </script>
}

<div>
    poo bar poo
</div>

<div>
  @Html.Partial("_myPartial")
</div>

أحتاج إلى إدخال بعض المحتوى داخل قسم Scripts من العرض الجزئي _myPartial .

كيف يمكنني أن أفعل هذا؟


إذا كان لديك حاجة مشروعة لتشغيل بعض js من partial ، فإليك كيفية القيام بذلك ، jQuery مطلوب:

<script type="text/javascript">        
    function scriptToExecute()
    {
        //The script you want to execute when page is ready.           
    }

    function runWhenReady()
    {
        if (window.$)
            scriptToExecute();                                   
        else
            setTimeout(runWhenReady, 100);
    }
    runWhenReady();
</script>

باتباع المبدأ غير المزعج ، ليس مطلوبًا تمامًا أن تقوم "_myPartial" بحقن المحتوى مباشرة في قسم البرامج النصية. يمكنك إضافة نصوص العرض الجزئية هذه إلى ملف .js منفصل وإحالتها إلى قسمscripts من عرض الوالدين.


باستخدام Mvc Core يمكنك إنشاء scripts TagHelper مرتبة كما هو موضح أدناه. هذا يمكن بسهولة أن تتحول إلى علامة section حيث تعطيها اسما كذلك (أو أخذ الاسم من النوع المشتق). لاحظ أنه يجب أن يكون إعداد IHttpContextAccessor .

عند إضافة نصوص (على سبيل المثال ، بشكل جزئي)

<scripts>
    <script type="text/javascript">
        //anything here
    </script>
</scripts>

عند إخراج البرامج النصية (على سبيل المثال في ملف تخطيطي)

<scripts render="true"></scripts>

الشفرة

public class ScriptsTagHelper : TagHelper
    {
        private static readonly object ITEMSKEY = new Object();

        private IDictionary<object, object> _items => _httpContextAccessor?.HttpContext?.Items;

        private IHttpContextAccessor _httpContextAccessor;

        public ScriptsTagHelper(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            var attribute = (TagHelperAttribute)null;
            context.AllAttributes.TryGetAttribute("render",out attribute);

            var render = false;

            if(attribute != null)
            {
                render = Convert.ToBoolean(attribute.Value.ToString());
            }

            if (render)
            {
                if (_items.ContainsKey(ITEMSKEY))
                {
                    var scripts = _items[ITEMSKEY] as List<HtmlString>;

                    var content = String.Concat(scripts);

                    output.Content.SetHtmlContent(content);
                }
            }
            else
            {
                List<HtmlString> list = null;

                if (!_items.ContainsKey(ITEMSKEY))
                {
                    list = new List<HtmlString>();
                    _items[ITEMSKEY] = list;
                }

                list = _items[ITEMSKEY] as List<HtmlString>;

                var content = await output.GetChildContentAsync();

                list.Add(new HtmlString(content.GetContent()));
            }
        }
    }

تفترض أن لديك طريقة عرض جزئية تسمى _contact.cshtml ، يمكن أن تكون جهة الاتصال الخاصة بك قانونية (اسم) أو موضوع فعلي (الاسم الأول ، اسم العائلة). يجب أن تهتم وجهة نظرك بما تم تقديمه والذي يمكن تحقيقه باستخدام javascript. قد تكون هناك حاجة لذلك تأخر تقديم و JS داخل الرأي.

الطريقة الوحيدة التي أفكر بها ، كيف يمكن الاستغناء عنها ، هي عندما ننشئ طريقة غير مزعجة للتعامل مع مخاوف واجهة المستخدم هذه.

نلاحظ أيضا أن MVC 6 سيكون لها ما يسمى بالمكون عرض ، حتى العقود الآجلة MVC لديها بعض الاشياء المماثلة و Telerik يدعم أيضا مثل هذا الشيء ...


حسنًا ، أعتقد أن الملصقات الأخرى قد وفرت لك وسيلة لتضمين @ section بشكل جزئي ضمن حسابك الجزئي (باستخدام مساعدين تابعين لـ html من جهة خارجية).

ولكن ، أعتقد أنه إذا كان البرنامج النصي الخاص بك مقترنًا بشكل جزئي بالجزء الجزئي الخاص بك ، فضع وضع javascript الخاص بك مباشرةً داخل علامة <script> مضمنة داخل جزئك <script> واجعله حيال ذلك (فقط كن حذراً من تكرار البرنامج النصي إذا كنت تنوي استخدام الجزء الجزئي أكثر من مرة في عرض واحد) ؛


كان لي مشكلة مماثلة حلها مع هذا:

@section ***{
@RenderSection("****", required: false)
}

هذا هو وسيلة جميلة لحق i guesse.


كان لي هذه المشكلة واستخدمت this التقنية.

في أفضل الحلول التي وجدتها مرنة للغاية.

يرجى أيضًا التصويت here لإضافة دعم لإعلان القسم التراكمي


لا يمكنك استخدام الأقسام في طريقة العرض الجزئي.

تضمين في طريقة العرض الجزئية. انها تنفذ وظيفة بعد jQuery تحميلها. يمكنك تبديل شرط الشرط الخاص بك.

<script type="text/javascript">    
var time = setInterval(function () {
    if (window.jQuery != undefined) {
        window.clearInterval(time);

        //Begin
        $(document).ready(function () {
           //....
        });
        //End
    };
}, 10); </script>

خوليو سبايدر


من الحلول في هذا الموضوع ، توصلت إلى الحل التالي الذي قد يكون أكثر تعقيدا والذي يتيح لك تأخير تقديم أي html (مخطوطات أيضا) داخل كتلة استخدام.

الاستعمال

أنشئ "القسم"

  1. السيناريو النموذجي: في طريقة العرض الجزئي ، قم بتضمين الكتلة مرة واحدة فقط بغض النظر عن عدد مرات تكرار العرض الجزئي في الصفحة:

    @using (Html.Delayed(isOnlyOne: "some unique name for this section")) {
        <script>
            someInlineScript();
        </script>
    }
    
  2. في طريقة العرض الجزئية ، ضمّن الحظر لكل مرة يتم فيها استخدام الجزء الجزئي:

    @using (Html.Delayed()) {
        <b>show me multiple times, @Model.Whatever</b>
    }
    
  3. في طريقة العرض الجزئي ، قم بتضمين الكتلة مرة واحدة فقط بغض النظر عن عدد المرات التي يتم فيها تكرار الجزء الجزئي ، ولكن قم بتجسيده لاحقًا بالاسم when-i-call-you :

    @using (Html.Delayed("when-i-call-you", isOnlyOne: "different unique name")) {
        <b>show me once by name</b>
        <span>@Model.First().Value</span>
    }
    

تقديم "المقاطع"

(أي عرض القسم المتأخر في عرض الوالدين)

@Html.RenderDelayed(); // writes unnamed sections (#1 and #2, excluding #3)
@Html.RenderDelayed("when-i-call-you", false); // writes the specified block, and ignore the `isOnlyOne` setting so we can dump it again
@Html.RenderDelayed("when-i-call-you"); // render the specified block by name
@Html.RenderDelayed("when-i-call-you"); // since it was "popped" in the last call, won't render anything due to `isOnlyOne` provided in `Html.Delayed`

الشفرة

public static class HtmlRenderExtensions {

    /// <summary>
    /// Delegate script/resource/etc injection until the end of the page
    /// <para>@via https://.com/a/14127332/1037948 and http://jadnb.wordpress.com/2011/02/16/rendering-scripts-from-partial-views-at-the-end-in-mvc/ </para>
    /// </summary>
    private class DelayedInjectionBlock : IDisposable {
        /// <summary>
        /// Unique internal storage key
        /// </summary>
        private const string CACHE_KEY = "DCCF8C78-2E36-4567-B0CF-FE052ACCE309"; // "DelayedInjectionBlocks";

        /// <summary>
        /// Internal storage identifier for remembering unique/isOnlyOne items
        /// </summary>
        private const string UNIQUE_IDENTIFIER_KEY = CACHE_KEY;

        /// <summary>
        /// What to use as internal storage identifier if no identifier provided (since we can't use null as key)
        /// </summary>
        private const string EMPTY_IDENTIFIER = "";

        /// <summary>
        /// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="identifier">optional unique sub-identifier for a given injection block</param>
        /// <returns>list of delayed-execution callbacks to render internal content</returns>
        public static Queue<string> GetQueue(HtmlHelper helper, string identifier = null) {
            return _GetOrSet(helper, new Queue<string>(), identifier ?? EMPTY_IDENTIFIER);
        }

        /// <summary>
        /// Retrieve a context-aware list of cached output delegates from the given helper; uses the helper's context rather than singleton HttpContext.Current.Items
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="defaultValue">the default value to return if the cached item isn't found or isn't the expected type; can also be used to set with an arbitrary value</param>
        /// <param name="identifier">optional unique sub-identifier for a given injection block</param>
        /// <returns>list of delayed-execution callbacks to render internal content</returns>
        private static T _GetOrSet<T>(HtmlHelper helper, T defaultValue, string identifier = EMPTY_IDENTIFIER) where T : class {
            var storage = GetStorage(helper);

            // return the stored item, or set it if it does not exist
            return (T) (storage.ContainsKey(identifier) ? storage[identifier] : (storage[identifier] = defaultValue));
        }

        /// <summary>
        /// Get the storage, but if it doesn't exist or isn't the expected type, then create a new "bucket"
        /// </summary>
        /// <param name="helper"></param>
        /// <returns></returns>
        public static Dictionary<string, object> GetStorage(HtmlHelper helper) {
            var storage = helper.ViewContext.HttpContext.Items[CACHE_KEY] as Dictionary<string, object>;
            if (storage == null) helper.ViewContext.HttpContext.Items[CACHE_KEY] = (storage = new Dictionary<string, object>());
            return storage;
        }


        private readonly HtmlHelper helper;
        private readonly string identifier;
        private readonly string isOnlyOne;

        /// <summary>
        /// Create a new using block from the given helper (used for trapping appropriate context)
        /// </summary>
        /// <param name="helper">the helper from which we use the context</param>
        /// <param name="identifier">optional unique identifier to specify one or many injection blocks</param>
        /// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
        public DelayedInjectionBlock(HtmlHelper helper, string identifier = null, string isOnlyOne = null) {
            this.helper = helper;

            // start a new writing context
            ((WebViewPage)this.helper.ViewDataContainer).OutputStack.Push(new StringWriter());

            this.identifier = identifier ?? EMPTY_IDENTIFIER;
            this.isOnlyOne = isOnlyOne;
        }

        /// <summary>
        /// Append the internal content to the context's cached list of output delegates
        /// </summary>
        public void Dispose() {
            // render the internal content of the injection block helper
            // make sure to pop from the stack rather than just render from the Writer
            // so it will remove it from regular rendering
            var content = ((WebViewPage)this.helper.ViewDataContainer).OutputStack;
            var renderedContent = content.Count == 0 ? string.Empty : content.Pop().ToString();
            // if we only want one, remove the existing
            var queue = GetQueue(this.helper, this.identifier);

            // get the index of the existing item from the alternate storage
            var existingIdentifiers = _GetOrSet(this.helper, new Dictionary<string, int>(), UNIQUE_IDENTIFIER_KEY);

            // only save the result if this isn't meant to be unique, or
            // if it's supposed to be unique and we haven't encountered this identifier before
            if( null == this.isOnlyOne || !existingIdentifiers.ContainsKey(this.isOnlyOne) ) {
                // remove the new writing context we created for this block
                // and save the output to the queue for later
                queue.Enqueue(renderedContent);

                // only remember this if supposed to
                if(null != this.isOnlyOne) existingIdentifiers[this.isOnlyOne] = queue.Count; // save the index, so we could remove it directly (if we want to use the last instance of the block rather than the first)
            }
        }
    }


    /// <summary>
    /// <para>Start a delayed-execution block of output -- this will be rendered/printed on the next call to <see cref="RenderDelayed"/>.</para>
    /// <para>
    /// <example>
    /// Print once in "default block" (usually rendered at end via <code>@Html.RenderDelayed()</code>).  Code:
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>show at later</b>
    ///     <span>@Model.Name</span>
    ///     etc
    /// }
    /// </code>
    /// </example>
    /// </para>
    /// <para>
    /// <example>
    /// Print once (i.e. if within a looped partial), using identified block via <code>@Html.RenderDelayed("one-time")</code>.  Code:
    /// <code>
    /// @using (Html.Delayed("one-time", isOnlyOne: "one-time")) {
    ///     <b>show me once</b>
    ///     <span>@Model.First().Value</span>
    /// }
    /// </code>
    /// </example>
    /// </para>
    /// </summary>
    /// <param name="helper">the helper from which we use the context</param>
    /// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
    /// <param name="isOnlyOne">extra identifier used to ensure that this item is only added once; if provided, content should only appear once in the page (i.e. only the first block called for this identifier is used)</param>
    /// <returns>using block to wrap delayed output</returns>
    public static IDisposable Delayed(this HtmlHelper helper, string injectionBlockId = null, string isOnlyOne = null) {
        return new DelayedInjectionBlock(helper, injectionBlockId, isOnlyOne);
    }

    /// <summary>
    /// Render all queued output blocks injected via <see cref="Delayed"/>.
    /// <para>
    /// <example>
    /// Print all delayed blocks using default identifier (i.e. not provided)
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>show me later</b>
    ///     <span>@Model.Name</span>
    ///     etc
    /// }
    /// </code>
    /// -- then later --
    /// <code>
    /// @using (Html.Delayed()) {
    ///     <b>more for later</b>
    ///     etc
    /// }
    /// </code>
    /// -- then later --
    /// <code>
    /// @Html.RenderDelayed() // will print both delayed blocks
    /// </code>
    /// </example>
    /// </para>
    /// <para>
    /// <example>
    /// Allow multiple repetitions of rendered blocks, using same <code>@Html.Delayed()...</code> as before.  Code:
    /// <code>
    /// @Html.RenderDelayed(removeAfterRendering: false); /* will print */
    /// @Html.RenderDelayed() /* will print again because not removed before */
    /// </code>
    /// </example>
    /// </para>

    /// </summary>
    /// <param name="helper">the helper from which we use the context</param>
    /// <param name="injectionBlockId">optional unique identifier to specify one or many injection blocks</param>
    /// <param name="removeAfterRendering">only render this once</param>
    /// <returns>rendered output content</returns>
    public static MvcHtmlString RenderDelayed(this HtmlHelper helper, string injectionBlockId = null, bool removeAfterRendering = true) {
        var stack = DelayedInjectionBlock.GetQueue(helper, injectionBlockId);

        if( removeAfterRendering ) {
            var sb = new StringBuilder(
#if DEBUG
                string.Format("<!-- delayed-block: {0} -->", injectionBlockId)
#endif
                );
            // .count faster than .any
            while (stack.Count > 0) {
                sb.AppendLine(stack.Dequeue());
            }
            return MvcHtmlString.Create(sb.ToString());
        } 

        return MvcHtmlString.Create(
#if DEBUG
                string.Format("<!-- delayed-block: {0} -->", injectionBlockId) + 
#endif
            string.Join(Environment.NewLine, stack));
    }


}

هذا عمل لي مما يتيح لي أن تشارك في تحديد موقع javascript و html لعرض جزئي في نفس الملف. يساعد في عملية التفكير لرؤية html والجزء ذي الصلة في نفس ملف العرض الجزئي.

في العرض الذي يستخدم طريقة العرض الجزئية التي تسمى "_MyPartialView.cshtml"

<div>
    @Html.Partial("_MyPartialView",< model for partial view>,
            new ViewDataDictionary { { "Region", "HTMLSection" } } })
</div>

@section scripts{

    @Html.Partial("_MyPartialView",<model for partial view>, 
                  new ViewDataDictionary { { "Region", "ScriptSection" } })

 }

في ملف العرض الجزئي

@model SomeType

@{
    var region = ViewData["Region"] as string;
}

@if (region == "HTMLSection")
{


}

@if (region == "ScriptSection")
{
        <script type="text/javascript">
    </script">
}

هناك خلل أساسي في الطريقة التي نفكر بها في الويب ، خاصة عند استخدام MVC. العيب هو أن جافا سكريبت هي بطريقة ما مسؤولية العرض. طريقة العرض هي ، جافا سكريبت (السلوكية أو غير ذلك) هو JavaScript. في نموذج سيلفرلايت و WPV's MVVM نحن نواجه "العرض الأول" أو "النموذج الأول". في MVC ، يجب أن نحاول دائمًا التفكير من وجهة نظر النموذج وجافا سكريبت هي جزء من هذا النموذج بعدة طرق.

أود أن أقترح استخدام نمط AMD (أنا نفسي مثل RequireJS ). تفحّص جافا سكريبت في الوحدات ، وحدد وظائفك واربطها في html من جافا سكريبت بدلاً من الاعتماد على عرض لتحميل جافا سكريبت. هذا سوف تنظيف التعليمات البرمجية الخاصة بك ، تفريق مخاوفك وجعل الحياة أسهل في ضربة واحدة.


واجهت مشكلة مماثلة ، حيث كان لدي صفحة رئيسية على النحو التالي:

@section Scripts {
<script>
    $(document).ready(function () {
        ...
    });
</script>
}

...

@Html.Partial("_Charts", Model)

لكن العرض الجزئي اعتمد على بعض JavaScript في قسم البرامج النصية. لقد قمت بحلها بترميز العرض الجزئي كـ JSON ، وتحميله في متغير جافا سكريبت ، ثم استخدام هذا لتجميع div ، لذلك:

@{
    var partial = Html.Raw(Json.Encode(new { html = Html.Partial("_Charts", Model).ToString() }));
}

@section Scripts {
<script>
    $(document).ready(function () {
        ...
        var partial = @partial;
        $('#partial').html(partial.html);
    });
</script>
}

<div id="partial"></div>

يمكنك استخدام هذه "أساليب ملحق" : (حفظ باسم PartialWithScript.cs)

namespace System.Web.Mvc.Html
{
    public static class PartialWithScript
    {
        public static void RenderPartialWithScript(this HtmlHelper htmlHelper, string partialViewName)
        {
            if (htmlHelper.ViewBag.ScriptPartials == null)
            {
                htmlHelper.ViewBag.ScriptPartials = new List<string>();
            }

            if (!htmlHelper.ViewBag.ScriptPartials.Contains(partialViewName))
            {
                htmlHelper.ViewBag.ScriptPartials.Add(partialViewName);
            }

            htmlHelper.ViewBag.ScriptPartialHtml = true;
            htmlHelper.RenderPartial(partialViewName);
        }

        public static void RenderPartialScripts(this HtmlHelper htmlHelper)
        {
            if (htmlHelper.ViewBag.ScriptPartials != null)
            {
                htmlHelper.ViewBag.ScriptPartialHtml = false;
                foreach (string partial in htmlHelper.ViewBag.ScriptPartials)
                {
                    htmlHelper.RenderPartial(partial);
                }
            }
        }
    }
}

استخدم مثل هذا:

مثال جزئي: (_MyPartial.cshtml) ضع html في if و js في آخر.

@if (ViewBag.ScriptPartialHtml ?? true)
    <p>I has htmls</p>
}
else {
    <script type="text/javascript">
        alert('I has javascripts');
    </script>
}

في _Layout.cshtml الخاص بك ، أو حيثما تريد أن يتم عرض النصوص البرمجية من الأجزاء الجزئية ، قم بوضع التالي (مرة واحدة): سيعرض فقط جافا سكريبت لكل الجزئيات الموجودة في الصفحة الحالية في هذا الموقع.

@{ Html.RenderPartialScripts(); }

ثم لاستخدام الجزئي الخاص بك ، ببساطة القيام بذلك: سيعرض فقط html في هذا الموقع.

@{Html.RenderPartialWithScript("~/Views/MyController/_MyPartial.cshtml");}




partial-views