रेजर व्यू इंजन के साथ एक आंशिक दृश्य ASP.NET MVC 3 से विशिष्ट खंडों में सामग्री को इंजेक्ट करना


324

मेरे पास यह खंड मेरे में परिभाषित है _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

मैं यह कैसे कर सकता हूँ?


17
इसके बाद आने वाले लोगों के लिए - इससे निपटने के लिए एक नगेट पैकेज है: nuget.org/packages/Forloop.HtmlHelpers
Russ Cam

@RussCam आपको इस सवाल का जवाब देना चाहिए। +1 नगेट पैकेज ओपी को होने वाली सटीक समस्या को हल करता है।
कैरी केंडल

1
@RussCam NuGet पैकेज एक समाधान नहीं है, पैकेज का कोड हो सकता है।
मक्सीम वी।

8
@MaksimVi। ठीक है, मैंने नगेट पैकेज लिखा है और इसे नीचे ले जाने का कोई इरादा नहीं है, इसलिए कोड दोहराने के बजाय ( bitbucket.org/forloop/forloop-htmlhelpers/src ) या विकी ( bitbucket.org/forloop/forloop-htmlhelpers/wiki) / होम ) यहां, एक टिप्पणी के रूप में इसका लिंक स्टैकओवरफ्लो की भावना के भीतर रहता है, आईएमओ।
रस कैम

यहाँ एक और समाधान है जो बहुत अच्छा लगता है: stackoverflow.com/questions/5355427/…
jkokorian

जवाबों:


235

अनुभाग आंशिक विचारों में काम नहीं करते हैं और यह डिजाइन द्वारा है। आप समान व्यवहार को प्राप्त करने के लिए कुछ कस्टम हेल्पर्स का उपयोग कर सकते हैं , लेकिन ईमानदारी से यह आवश्यक स्क्रिप्ट को शामिल करने की जिम्मेदारी है, न कि आंशिक जिम्मेदारी की। मैं ऐसा करने के लिए मुख्य दृश्य के @ खंडों का उपयोग करने की सलाह दूंगा और लिपियों के बारे में चिंता नहीं करनी चाहिए।


445
लेकिन क्या होगा अगर स्क्रिप्ट आंशिक के लिए बहुत विशिष्ट है? क्या इसे आंशिक रूप से परिभाषित करने के लिए तार्किक अर्थ नहीं है, न कि दृश्य?
जेज

43
यह डिजाइन द्वारा क्यों है?
शिम्मी वेइटहैंडलर

56
@ डारिन: मैं असहमत हूं। DRY सिद्धांत के बारे में क्या? मुझे खुद को दोहराना पसंद नहीं है, भले ही यह केवल स्क्रिप्ट संदर्भ हो।
fretje

14
@fretje, हर किसी को विषय पर अपनी राय व्यक्त करने का अधिकार है। मैं आपका सम्मान करता हूं। मेरे उत्तर में मैंने अपना विचार व्यक्त किया है और एक ऐसे उत्तर से जुड़ा हूं जो आपको इस कार्य को प्राप्त करने की अनुमति देगा। लेकिन मैंने इस बात पर भी प्रकाश डाला है कि मैं इस स्थिति के लिए क्या सलाह दूंगा और क्या करूंगा।
डारिन दिमित्रोव

33
@JoshNoe और बाकी को सुरक्षित करना - एक "विजेट" (प्रदर्शन + समृद्ध इंटरैक्शन) आंशिक रूप से संबंधित जावास्क्रिप्ट को युग्मित आंशिक दृश्य का एक आदर्श उदाहरण है। डिज़ाइन के अनुसार, मुझे पूर्ण कार्यक्षमता प्राप्त करने के लिए अलग-अलग स्थानों में दो को शामिल नहीं करना चाहिए, क्योंकि प्रदर्शन कभी भी सहभागी सहभागिता के बिना नहीं होगा, और इंटरैक्शन कभी भी कहीं और दिखाई नहीं देगा।
drzaus

83

यह काफी लोकप्रिय सवाल है, इसलिए मैं अपना समाधान पोस्ट करूंगा।
मेरे पास एक ही समस्या थी और हालांकि यह आदर्श नहीं है, मुझे लगता है कि यह वास्तव में काफी अच्छी तरह से काम करता है और दृश्य पर आंशिक निर्भर नहीं करता है।
मेरा परिदृश्य यह था कि एक कार्रवाई स्वयं द्वारा सुलभ थी, लेकिन यह भी एक दृश्य में एम्बेड किया जा सकता है - एक Google मानचित्र।

मेरे _layoutपास में:

@RenderSection("body_scripts", false)

मेरे indexविचार में मेरे पास है:

@Html.Partial("Clients")
@section body_scripts
{
    @Html.Partial("Clients_Scripts")
}

मेरे clientsविचार में मेरे पास (सभी मानचित्र और गधे। html):

@section body_scripts
{
    @Html.Partial("Clients_Scripts")
}

मेरे Clients_Scriptsविचार में पृष्ठ पर प्रदान की जाने वाली जावास्क्रिप्ट शामिल है

इस तरह मेरी स्क्रिप्ट अलग-थलग हो जाती है और जहां आवश्यक हो, उस पेज में रेंडर किया जा सकता है, जिसमें body_scriptsटैग केवल पहली घटना पर रेंडर किया जाता है जो रेजर व्यू इंजन को मिल जाता है।

इससे मुझे सब कुछ अलग हो गया - यह एक समाधान है जो मेरे लिए बहुत अच्छा काम करता है, दूसरों के पास इसके साथ समस्या हो सकती है, लेकिन यह "डिज़ाइन द्वारा" छेद को पैच करता है।


2
मैं आपको वोट देने वाला नहीं था, लेकिन मैं कहूंगा कि मुझे वास्तव में यह समाधान पसंद नहीं है क्योंकि यह अभी भी विशिष्ट स्क्रिप्ट को दृश्य से अलग करता है।
क्रश

3
20 अन्य लोगों और मेरी एक अलग राय है। आप अभी भी स्क्रिप्ट को सीधे एक दृश्य से संबंधित कर सकते हैं जो एक अलग फ़ाइल में हैं, यह एक प्रोग्रामिंग त्रुटि है यदि आप अपनी स्क्रिप्ट को अपने दृश्य के साथ शामिल नहीं करते हैं। इसे एक अलग फाइल में रखने से इंटरेक्शन को प्रेजेंटेशन से अलग कर दिया जाता है और इससे अन्य फायदों की भरमार होती है।
दान रिचारडसन

1
आप पूरी तरह से सही हैं। मैं वास्तव में पूरी तरह से सहमत हूं और इस पद्धति को व्यक्तिगत रूप से पसंद करता हूं। मेरे लिए असली समस्या यह है कि मेरे सहकर्मी इस अलगाव से जूझते हैं। हालांकि यह एक डोमेन समस्या है। मुझे लगता है कि यह विधि आदर्श है, विशेष रूप से एक बार जब आप जावास्क्रिप्ट निर्माण प्रक्रिया में कारक होते हैं। मैं अपने सहयोगियों को इस पद्धति का उपयोग करने के लिए शिक्षित करने पर काम करना जारी रखूंगा, और इसका पूर्ण समर्थन करूंगा। मुझे लगता है कि आपके उत्तर में सुधार किया जा सकता है, हालांकि। हालाँकि आपको "20 लोग सहमत" का उल्लेख करने की आवश्यकता नहीं थी। सिर्फ इसलिए कि एक उत्तर लोकप्रिय है, हमेशा इसका मतलब यह नहीं है कि यह सही है। इस मामले में यह सही है।
क्रश करें

बहुत सच है, और मैं रचनात्मक प्रतिक्रिया को स्वीकार करने और अपने स्वयं के कोड को बदलने और अगर कोई सुधार होना है, तो मुझे हमेशा खुशी होती है :)
dan richardson

1
इस समाधान में अभी भी सभी MVC-ish सामान है कि आप एक विशिष्ट दृश्य में करने में सक्षम होने की उम्मीद है, जैसे कि JSON करने में सक्षम होने के रूप में मॉडल में एक पारित सांकेतिक शब्दों में बदलना और यूआरएल का उपयोग कर उत्पन्न करने में सक्षम होने का जोड़ा लाभ है। कार्रवाई। यह दृष्टिकोण तब अपने AngularJS नियंत्रकों को स्थापित करने का एक सुंदर तरीका है - प्रत्येक आंशिक दृश्य कोणीय मॉड्यूल में एक अलग नियंत्रक का प्रतिनिधित्व कर सकता है। इतना साफ!
दान

40

इस सूत्र में समाधान से , मैं निम्नलिखित संभवतः अतिव्यापी समाधान के साथ आया था जो आपको एक प्रयोग ब्लॉक के भीतर किसी भी 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://stackoverflow.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));
    }


}

1
वाह यह भी मेरे लिए कोड को समझने के लिए जटिल है, लेकिन एक समाधान के साथ आने के लिए +1
रमीज अहमद सयाद

@RameezAhmedSayad आप सही हैं - यहाँ वापस आ रहे हैं यहां तक ​​कि मैं उलझन में हूँ कि मैं यह कैसे कहने का मतलब है कि इसका उपयोग कैसे करें। उत्तर को अपडेट कर रहा है ...
drzaus

और आगे स्पष्ट करने के लिए - कारण दो "नाम" हैं यदि आप केवल यह चाहते हैं कि इसे एक बार प्रदान किया जाए, तो इसे पैरामीटर में अद्वितीय कुंजी की आवश्यकता होती है isOnlyOne, लेकिन केवल यदि आप इसे किसी विशिष्ट स्थान पर प्रस्तुत करना चाहते हैं तो आप इसे पहचानकर्ता प्रदान करेंगे, अन्यथा यह डंप हो जाता है Html.RenderDelayed()
ड्रूज़

मुझे नहीं लगता कि परेशानी को खरीदने और इस दृष्टिकोण का उपयोग करने के लिए कोई आवश्यकता होगी, आंशिक विचारों में अनुभाग की आवश्यकता नहीं है क्योंकि इसे समाप्त किया जा सकता है, और स्क्रिप्ट एक खंड को परिभाषित किए बिना वहां जा सकते हैं। इसका कारण यह है कि यह बाहरी रूप से प्रदान किया गया है और यदि आप प्रदान किए गए पृष्ठ के लिए कोड देखते हैं तो आपको बस आंशिक दृश्य के लिए कोड दिखाई नहीं देता है। तो अगर यह बेहतर संगठन, आदि की बात है, तो इसका कोई प्रभाव नहीं पड़ेगा।
उत्कृष्ट

@ ट्रान्ससेन्ट "बहस" को पहले से ही स्वीकृत जवाब stackoverflow.com/a/7556594/1037948
drzaus

16

मुझे यह समस्या थी और मैंने इस तकनीक का इस्तेमाल किया ।

इसका सबसे अच्छा समाधान मैंने पाया जो बहुत लचीला है।

इसके अलावा वोट करें यहाँ संचयी अनुभाग घोषणा के लिए समर्थन जोड़ने के लिए


9

यदि आपको कुछ को चलाने की वैध आवश्यकता 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>

मैंने @drzaus की कोशिश की, इसे 'SeeIfReady' की जरूरत है या यह काम नहीं करता है।
काचो सांता

8

विनीत सिद्धांत के बाद , स्क्रिप्ट अनुभाग में सीधे सामग्री को इंजेक्ट करने के लिए "_myPartial" के लिए इसकी बहुत आवश्यकता नहीं है। आप उन आंशिक दृश्य लिपियों को अलग .jsफ़ाइल में जोड़ सकते हैं और उन्हें मूल दृश्य से @ वर्णनों अनुभाग में संदर्भित कर सकते हैं।


10
यदि आंशिक दृश्य पृष्ठ में प्रदान नहीं किया गया है तो क्या होगा? क्या हम अभी भी उन .js फ़ाइलों को जनक में संदर्भित करते हैं और इसे अधिभारित करते हैं?
मुरली मुरुगेसन

5

वेब के बारे में सोचने के तरीके में एक मूलभूत दोष है, खासकर एमवीसी का उपयोग करते समय। दोष यह है कि जावास्क्रिप्ट किसी तरह से दृश्य की जिम्मेदारी है। एक दृश्य एक दृश्य है, जावास्क्रिप्ट (व्यवहार या अन्यथा) जावास्क्रिप्ट है। सिल्वरलाइट और डब्ल्यूपीएफ के एमवीवीएम पैटर्न में हम "पहले देखें" या "मॉडल पहले" के साथ सामना कर रहे हैं। MVC में हमें हमेशा मॉडल के दृष्टिकोण से तर्क करने की कोशिश करनी चाहिए और जावास्क्रिप्ट कई मायनों में इस मॉडल का एक हिस्सा है।

मैं एएमडी पैटर्न का उपयोग करने का सुझाव दूंगा (मैं खुद की आवश्यकता है )। अपने जावास्क्रिप्ट को मॉड्यूल में अलग करें, जावास्क्रिप्ट को लोड करने की दृष्टि पर निर्भर होने के बजाय जावास्क्रिप्ट से अपनी कार्यक्षमता और हुक को अपने html में परिभाषित करें। यह आपके कोड को साफ करेगा, आपकी चिंताओं को अलग करेगा और एक झपट्टा में जीवन को आसान बना देगा।


दो या तीन महीने या तो के लिए, मैं आवश्यकताजे का उपयोग कर रहा हूं और मुझे नहीं लगता कि मैं कभी भी बिना आवश्यकता के एक और वेब एप्लिकेशन विकसित करूंगा।
टगबरक

6
जावास्क्रिप्ट भी जिम्मेदारी देख सकते हैं।
केलमेन

1
एएमडी पैटर्न का उपयोग करना एक अच्छा विचार है, लेकिन मैं आपके दावे से सहमत नहीं हूं कि जावास्क्रिप्ट मॉडल का हिस्सा है। यह अक्सर दृश्य व्यवहार को परिभाषित करने के लिए होता है, खासकर जब नॉकआउट जैसी किसी चीज़ के साथ युग्मित किया जाता है। आप अपने जावास्क्रिप्ट दृश्य में अपने मॉडल का एक JSON प्रतिनिधित्व डंप करते हैं। व्यक्तिगत रूप से, मैं बस क्लोजर का उपयोग करता हूं, windowऑब्जेक्ट पर एक कस्टम "नामस्थान" , और किसी भी धारावाहिक से पहले लाइब्रेरी स्क्रिप्ट शामिल करता हूं ।
क्रश

मुझे लगता है कि यहां गलतफहमी है। अधिकांश वेब एप्लिकेशन विकसित करते समय, हम वास्तव में दो एप्लिकेशन विकसित कर रहे हैं : एक जो सर्वर पर चलता है और एक जो क्लाइंट पर चलता है। सर्वर के दृष्टिकोण से, आप ब्राउज़र में जो कुछ भी भेजते हैं, वह "दृश्य" है। उस अर्थ में, जावास्क्रिप्ट दृश्य का हिस्सा है। क्लाइंट ऐप के दृष्टिकोण से, शुद्ध HTML दृश्य है और जेएस कोड है जो सर्वर के एमवीसी शब्दों में एम और सी को समानता देता है। मुझे लगता है कि यही कारण है कि लोग यहां असहमत हैं।
बजे

3

ओपी का लक्ष्य यह है कि वह इनलाइन स्क्रिप्ट को अपने आंशिक दृश्य में परिभाषित करना चाहता है, जो मुझे लगता है कि यह स्क्रिप्ट केवल उस आंशिक दृश्य के लिए विशिष्ट है, और उस ब्लॉक को उसकी स्क्रिप्ट अनुभाग में शामिल किया गया है।

मुझे लगता है कि वह चाहता है कि आंशिक दृश्य आत्म निहित हो। कोणीय का उपयोग करते समय विचार घटकों के समान है।

मेरा तरीका सिर्फ आंशिक दृश्य के अंदर स्क्रिप्ट रखने के लिए होगा। अब आंशिक समस्या यह है कि आंशिक दृश्य कहते समय, यह अन्य सभी लिपियों से पहले स्क्रिप्ट को निष्पादित कर सकता है (जो आमतौर पर लेआउट पृष्ठ के नीचे जोड़ा जाता है)। उस स्थिति में, आपके पास अन्य स्क्रिप्ट के लिए आंशिक दृश्य स्क्रिप्ट प्रतीक्षा है। इसे करने बहुत सारे तरीके हैं। सबसे सरल एक, जिसका मैंने पहले उपयोग किया है, एक घटना का उपयोग कर रहा हैbody

मेरे लेआउट पर, मेरे पास इस तरह से नीचे कुछ होगा:

// global scripts
<script src="js/jquery.min.js"></script>
// view scripts
@RenderSection("scripts", false)
// then finally trigger partial view scripts
<script>
  (function(){
    document.querySelector('body').dispatchEvent(new Event('scriptsLoaded'));
  })();
</script>

फिर मेरे आंशिक दृश्य पर (नीचे):

<script>
  (function(){
    document.querySelector('body').addEventListener('scriptsLoaded', function() {

      // .. do your thing here

    });
  })();
</script>

एक अन्य समाधान आपके सभी लिपियों को पुश करने के लिए एक स्टैक का उपयोग कर रहा है, और अंत में प्रत्येक को कॉल करें। अन्य समाधान, जैसा कि पहले ही उल्लेख किया गया है, आवश्यकताएँ / एएमडी पैटर्न है, जो वास्तव में भी अच्छी तरह से काम करता है।


2

पहला उपाय जिसके बारे में मैं सोच सकता हूं, वह है उन मूल्यों को संग्रहीत करने के लिए ViewBag का उपयोग करना।

इसके बाद, मैंने कभी यह कोशिश नहीं की कि यह एक आंशिक दृष्टिकोण से काम करे, लेकिन इसे इमो करना चाहिए।


प्रयास किया; दुख की बात है कि यह काम नहीं करता है ( ViewBag.RenderScripts = new List<string>();मुख्य पृष्ठ के शीर्ष पर बनाया गया, फिर कॉल किया गया @Html.Partial("_CreateUpdatePartial",Model,ViewData), फिर डाल दिया गया @section Scripts {@foreach (string script in ViewBag.RenderScripts) Scripts.Render(script); }}। आंशिक रूप से मैंने देखा @{ViewBag.RenderScripts = ViewBag.RenderScripts ?? new List<string>();ViewBag.RenderScripts.Add("~/bundles/jquery");}
JohnLevan

2

आपको आंशिक दृश्य में अनुभागों का उपयोग करने की आवश्यकता नहीं है।

अपने आंशिक दृश्य में शामिल करें। यह jQuery लोड होने के बाद फ़ंक्शन को निष्पादित करता है। आप अपने कोड के लिए डी कंडीशन क्लॉज को बदल सकते हैं।

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

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

जूलियो स्पैडर


2

आप इन एक्सटेंशन विधियों का उपयोग कर सकते हैं : (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);
                }
            }
        }
    }
}

इस तरह का उपयोग करें:

उदाहरण आंशिक: (_MPPialial.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");}

1

आंशिक विचारों में अनुभाग सम्मिलित करने का एक तरीका है, हालांकि यह सुंदर नहीं है। आपको पेरेंट व्यू से दो वेरिएबल्स तक पहुंच की आवश्यकता है। चूँकि आपके आंशिक दृश्य का भाग उस उद्देश्य को बनाना है, इसलिए इन चरों की आवश्यकता समझ में आती है।

आंशिक दृश्य में एक अनुभाग सम्मिलित करने के लिए यह कैसा दिखता है:

@model KeyValuePair<WebPageBase, HtmlHelper>
@{
    Model.Key.DefineSection("SectionNameGoesHere", () =>
    {
        Model.Value.ViewContext.Writer.Write("Test");
    });
}

और पृष्ठ में आंशिक दृश्य सम्मिलित कर रहा है ...

@Html.Partial(new KeyValuePair<WebPageBase, HtmlHelper>(this, Html))

आप किसी भी वर्ग में प्रोग्राम की सामग्री को परिभाषित करने के लिए इस तकनीक का उपयोग कर सकते हैं।

का आनंद लें!


1
क्या आप कृपया और पूरी तरह से काम कर रहे प्रोजेक्ट के लिए लिंक कर सकते हैं?
एहसान जरगर इरशादी

1

एक अच्छे तरीके से प्लूटो का विचार:

CustomWebViewPage.cs:

    public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> {

    public IHtmlString PartialWithScripts(string partialViewName, object model) {
        return Html.Partial(partialViewName: partialViewName, model: model, viewData: new ViewDataDictionary { ["view"] = this, ["html"] = Html });
    }

    public void RenderScriptsInBasePage(HelperResult scripts) {
        var parentView = ViewBag.view as WebPageBase;
        var parentHtml = ViewBag.html as HtmlHelper;
        parentView.DefineSection("scripts", () => {
            parentHtml.ViewContext.Writer.Write(scripts.ToHtmlString());
        });
    }
}

दृश्य \ web.config:

<pages pageBaseType="Web.Helpers.CustomWebViewPage">

राय:

@PartialWithScripts("_BackendSearchForm")

आंशिक (_BackendSearchForm.cshtml):

@{ RenderScriptsInBasePage(scripts()); }

@helper scripts() {
<script>
    //code will be rendered in a "scripts" section of the Layout page
</script>
}

लेआउट पृष्ठ:

@RenderSection("scripts", required: false)

1

इसने मेरे लिए काम किया और मुझे एक ही फाइल में आंशिक दृश्य के लिए जावास्क्रिप्ट और 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">
}

0

मैंने इसे पूरी तरह से अलग रास्ता दिया (क्योंकि मैं जल्दी में था और एक नया HtmlHelper लागू नहीं करना चाहता था):

मैंने अपने आंशिक दृश्य को एक बड़े विवरण में लपेटा है,

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

फिर, मैंने एक कस्टम व्यूडेटा के साथ दो बार आंशिक कॉल किया:

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

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

निश्चित रूप से संपूर्ण विचार यह है कि आंशिक दृश्य के उपभोक्ता को यह जानने की आवश्यकता नहीं होनी चाहिए कि उसे स्क्रिप्ट शामिल करना है, यह समस्या का थोथा है? अन्यथा आप जैसा भी कह सकते हैं @Html.Partial("MyPartialViewScripts")
dan richardson

नहीं, यह विचार है कि स्क्रिप्ट को HTML के समान दस्तावेज़ में परिभाषित करने की अनुमति दी जाए, लेकिन मैं मानता हूं कि यह आदर्श नहीं है।
रिक लव

0

मेरे पास एक समान समस्या थी, जहां मेरे पास एक मास्टर पृष्ठ इस प्रकार था:

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

...

@Html.Partial("_Charts", Model)

लेकिन आंशिक दृश्य स्क्रिप्ट अनुभाग में कुछ जावास्क्रिप्ट पर निर्भर करता था। मैंने इसे 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>

IMO आपको अपने JS को एक अलग फ़ाइल में ले जाकर इसे हल करना चाहिए था।
वर्थि 7

0

स्पष्ट रूप से, आप अपने Folder / index.cshtml को एक मास्टरपेज के रूप में उपयोग कर सकते हैं, फिर अनुभाग स्क्रिप्ट जोड़ सकते हैं। फिर, आपके पास आपके लेआउट में:

@RenderSection("scripts", required: false) 

और आपका index.cshtml:

@section scripts{
     @Scripts.Render("~/Scripts/file.js")
}

और यह आपके सभी साक्षात्कारों पर काम करेगा। यह मेरे लिए काम करता है


0

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()));
            }
        }
    }

-1

ठीक है, मुझे लगता है कि अन्य पोस्टरों ने आपको सीधे अपने आंशिक (तृतीय पक्ष html हेल्पर्स का उपयोग करके) में एक @section शामिल करने का साधन प्रदान किया है।

लेकिन, मुझे लगता है कि, यदि आपकी स्क्रिप्ट आपके आंशिक रूप से युग्मित है, तो बस अपने जावास्क्रिप्ट को सीधे अपने इनलाइन <script>टैग के अंदर डालें और इसे अपने साथ कर लें (यदि आप आंशिक रूप से एक से अधिक बार उपयोग करने का इरादा रखते हैं, तो स्क्रिप्ट के दोहराव से सावधान रहें एक दृश्य में);


1
यह आमतौर पर आदर्श नहीं है क्योंकि इनलाइन स्क्रिप्ट के बाद jQuery आदि का लोडिंग होता है ... लेकिन देशी कोड के लिए मुझे लगता है कि यह ठीक है।
वर्थि 7

-3

मान लें कि आपके पास एक आंशिक दृश्य है, जिसे _contact.cshtml कहा जाता है, आपका संपर्क एक कानूनी (नाम) या भौतिक विषय (पहला नाम, अंतिम नाम) हो सकता है। आपके विचार को इस बात का ध्यान रखना चाहिए कि क्या प्रदान किया गया है और इसे जावास्क्रिप्ट के साथ प्राप्त किया जा सकता है। इसलिए विलंबित रेंडरिंग और JS को अंदर के दृश्य की आवश्यकता हो सकती है।

एकमात्र तरीका मुझे लगता है, यह कैसे किया जा सकता है, जब हम ऐसे UI चिंताओं से निपटने का एक विनीत तरीका बनाते हैं।

यह भी ध्यान दें कि एमवीसी 6 में एक तथाकथित व्यू कंपोनेंट होगा, यहां तक ​​कि एमवीसी वायदा में भी कुछ इसी तरह का सामान था और टेलरिक भी इस तरह का समर्थन करता है ...


1
3 साल की देरी, और मुझे नहीं लगता कि यह भी सवाल का जवाब देता है? आप यहाँ क्या कहना चाह रहे हैं? 3 साल बाद एक सवाल का जवाब देते हुए भविष्य की तकनीकों की सट्टा सुविधाओं के साथ वास्तव में एक उत्तर या विशेष रूप से उपयोगी नहीं है
dan richardson

-3

मैंने इस कोड को अपने आंशिक दृश्य में जोड़ा है और समस्या को हल किया है, हालांकि बहुत साफ नहीं है, यह काम करता है। आपको यह सुनिश्चित करना होगा कि आप जिन वस्तुओं का प्रतिपादन कर रहे हैं, उनमें से Ids।

<script>
    $(document).ready(function () {
        $("#Profile_ProfileID").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
        $("#TitleID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
        $("#CityID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
        $("#GenderID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
        $("#PackageID_FK").selectmenu({ icons: { button: 'ui-icon-circle-arrow-s' } });
    });
</script>

-5

मैं इसी तरह की समस्या के साथ इसे हल किया था:

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

मैं एक अच्छा तरीका है मुझे लगता है इंजेक्षन।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.