مطالب
معرفی Selector های CSS - قسمت 2
11- S1,S2
اگر بخواهیم قالب بندی را برای چند Selector به صورت یکجا انجام دهیم، این Selector‌ها را با کاما (,) از هم جدا می‌نماییم.
<style>
    div,.content,table.main {
        color: red;
    }
</style>
<div>Text 1</div>
<p>Text 2</p>
<table class="main" border="1">
    <tr>
        <td>Cell 1</td>
        <td>Cell 2</td>
        <td>Cell 3</td>
    </tr>
    <tr>
        <td>Cell 4</td>
        <td>Cell 5</td>
        <td>Cell 6</td>
    </tr>
</table>
<span class="content">Text 3</span>
<h1>Text 4</h1>
در مثال فوق Text 1 و Text 3 و همچنین محتوای تگ table به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 Yes  Yes  Yes Yes   Yes S1,S2  1
توجه:
Selector‌ها می‌توانند به صورت ترکیبی نیز استفاده شوند. به مثال زیر توجه کنید:
<style>
    .content .tag {
        color: red;
    }

    h1#index {
        color: blue;
    }

    ul.list li.even {
        color: green;
    }
</style>
<h1 id="index">Index</h1>
<h1>Header 1</h1>
<div class="content">
    Lorem ipsum dolor sit amet, <span class="tag">consectetuer</span> adipiscing elit.
    Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies,
    purus lectus malesuada libero, <span class="tag">sit</span> amet commodo magna 
    eros quis urna. Nunc viverra <span class="tag">imperdiet</span> enim. Fusce est.
</div>
<h1>Header 2</h1>
<div class="content">
    <ul class="list">
        <li>Item 1</li>
        <li class="even">Item 2</li>
        <li>Item 3</li>
        <li class="even">Item 4</li>
        <li>Item 5</li>
        <li class="even">Item 6</li>
    </ul>
</div>
در مثال فوق، تگ h1 که ویژگی id آن برابر index می‌باشد، با توجه به Selector ی که بصورت h1#index تعریف شده است، به رنگ آبی نمایش می‌یابد. تمامی تگ‌های span که عضو کلاس tag می‌باشند و در داخل تگ div ی قرار دارند که عضو کلاس content است، با توجه به Selector ی که بصورت .content .tag تعریف شده است، به رنگ قرمز نمایش می‌یابند. تمامی تگهای li که ویژگی class آنها برابر even می‌باشد، و فرزند تگ ul ی هستند که عضو کلاس list است، با توجه به Selector ی که بصورت ul.list li.even تعریف شده است، به رنگ سبز نمایش می‌یابند.

12- [attribute]

تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص باشند.
<style>
    [readonly] {
        background: green;
    }
</style>
<input type="text" value="Value 1" readonly="readonly"/>
<input type="text"/>
در مثال فوق، رنگ پس زمینه تگ input اول که دارای ویژگی readonly می‌باشد، به رنگ سبز نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute]    2

13- 
 [attribute=value] 
تگ هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی دقیقا برابر با value می‌باشد.
<style>
    [lang=fa] {
        direction:rtl;
    }
</style>
<div lang="fa">متن 1</div>
در مثال فوق، جهت نوشتاری محتوای تگ div که دارای ویژگی lang با مقدار fa می‌باشد، از راست به چپ می‌شود و در سمت راست صفحه نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1 9.6 7.0 2.0 4.0 [attribute=value] 
 2

14-
   [attribute=value i]
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی دقیقا برابر با value می‌باشد. همچنین value، نسبت به حروف کوچک و بزرگ حساس نمی‌باشد. 
<style>
    [lang=fa] {
        direction:rtl;
    }
</style>
<div lang="FA">متن 1</div>
در مثال فوق، جهت نوشتاری محتوای تگ div که دارای ویژگی lang با مقدار FA می‌باشد، از راست به چپ می‌شود و در سمت راست صفحه نمایش می‌یابد. با اینکه در Selector مقدار fa با حروف کوچک ذکر شده است.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No [attribute=value i] 
 4

15- 
 [attribute|=value] 
تگ هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی با یک value خاص آغاز می‌شود. کلمه آغازین مقدار حتما باید با value برابر باشد یا با dash (-) از کلمه‌ی بعدی جدا شده باشد.
<style>
    [class|=info] {
        color:red
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 4 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute|=value] 
 2

16- 
 [attribute^=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی با یک value خاص آغاز می شود.
<style>
    [class^=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 2 و Text 3 و Text 4 به رنگ قرمز نمایش می‌یابند. 
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute^=value] 
 3

17- 
 [attribute~=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی شامل یک value خاص می‌باشد که با Space یا فاصله‌ی خالی از سایر مقادیر جدا شده است. 
<style>
    [class~=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 3 و Text 6 و Text 9 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute~=value] 
 2

18- 
 [attribute*=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی شامل یک value خاص می‌باشد. 
<style>
    [class*=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق تمامی متون به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute*=value] 
 3

19- 
[attribute$=value]
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی به یک value خاص ختم می‌شود. 
<style>
    [class$=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مقال فوق Text 1 و Text 5 و Text 6 و Text 7 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute$=value] 
 3   
مطالب
کامپوننت‌ها در Vue.js
پیش‌تر در سایت مطالبی در رابطه با فریم‌ورک Vue.js منتشر شده‌است. در این مطلب می‌خواهیم نگاهی بر مفهوم کامپوننت‌ها در Vue بیندازیم و نحوه‌ی استفاده از آنها را بررسی کنیم.

قبل از معرفی کامپوننت‌ها اجازه دهید سیستم template در ویو را بررسی کنیم. سیستم template ویو براساس سینتکس HTML است:
new Vue({
  el: '#app',
  template: '<div>Hello DNT</div>'
});
البته استفاده از template کاملاً اختیاری است. بجای آن می‌توانیم از تابع رندر (همانند React) نیز استفاده کنیم:
new Vue({
    el: '#app',
    data() {
        return {
            blogTitle: 'DNT'
        }
    },
    render: function (createElement) {
        return createElement('h1', this.blogTitle)
    }
});

ایجاد یک کامپوننت ساده:
Vue.component('child', {
    template: '<div>Hello DNT users</div>'
});
در اینجا برای ایجاد یک کامپوننت، از تابع component استفاده کرده‌ایم؛ پارامتر اول این تابع، نام کامپوننت است و پارامتر دوم نیز یک شیء است. درون این شیء می‌توانیم قالب کامپوننت را تعیین کنیم. برای کامپوننت نیز می‌توانیم یک پارامتر ورودی را تعیین کنیم. اینکار را توسط مفهومی به نام Props می‌توانیم انجام دهیم:
Vue.component('child', {
    props: ['text'],
    template: `<div> {{ text }} </div>`
});

new Vue({
    el: '#app',
    data() {
        return {
            message: 'Hello DNT!'
        }
    }
});
اکنون می‌توانیم پارامتر موردنظر را به text، به عنوان ورودی کامپوننت ارسال کنیم (در واقع دیتای موجود در parent را به کامپوننت child ارسال کرده‌ایم):
<child :text="message"></child>

اعتبارسنجی پراپرتی‌ها
برای props می‌توانیم اعتبارسنجی را نیز انجام دهیم:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            required: true
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});
در اینجا نوع خاصیت post باید شیء باشد و همچنین آن را به صورت required تعریف کرده‌ایم. در این حالت اگر مقداری به غیر از شیء را به آن ارسال کنیم، خطای زیر را در کنسول دریافت خواهیم کرد:
[Vue warn]: Invalid prop: type check failed for prop "post". Expected Object, got String.

found in

---> <BlogPost>
       <Root>

همچنین می‌توانیم نوع اعتبارسنجی را به صورت سفارشی نیز تعیین کنیم:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            required: true,
            validator: obj => {
                const titleIsValid = typeof obj.title === 'string';
                const bodyIsValid = typeof obj.body === 'string';
                const isValid = titleIsValid && bodyIsValid;
                if (!isValid) {
                    console.warn("prop is not valid");
                    return false;
                }
                return true;
            }
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});

تعیین مقدار پیش‌فرض برای پراپرتی
برای یک prop می‌توانیم مقدار پیش‌فرضی را نیز تعیین کنیم. یعنی در صورت عدم ارسال شیء می‌توانیم تعیین کنیم که چه شیء‌ایی در حالت پیش‌فرض نمایش داده شود:
Vue.component('blogPost', {
    props: {
        post: {
            type: Object,
            validator: obj => {
                const titleIsValid = typeof obj.title === 'string';
                const bodyIsValid = typeof obj.body === 'string';
                const isValid = titleIsValid && bodyIsValid;
                if (!isValid) {
                    console.warn("prop is not valid");
                    return false;
                }
                return true;
            },
            default: function() {
                return {
                    title: 'Vue is fun!',
                    body: 'Vue is fun..................'
                }
            }
        }
    },
    template: `<div>
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
               </div>`
});

استفاده از دیتا درون کامپوننت
درون یک کامپوننت نیز می‌توانیم یکسری دیتا را تعریف کنیم. اما باید در نظر داشته باشید که هر وهله از کامپوننت، scope مجزای خودش را دارد. در نتیجه پیشنهاد میشود دیتا حتماً به صورت یک تابع تعریف شود و همچنین داده‌های درون آن نیز در scope کامپوننت تعریف شوند:
data: function () {
    return {
        stars: 5,
        hover: 5
    }
},
زیرا در صورت تعریف داده‌ها در خارج از scope کامپوننت، محتویات دیتا برای دیگر وهله‌های کامپوننت‌ها نیز به اشتراک گذاشته می‌شود. به عنوان مثال فرض کنید درون کامپوننت بلاگ‌پست، یک سیستم امتیاز دهی قرار داده‌ایم:
var dt = {
    stars: 5,
    hover: 5
};
Vue.component('blogPost', {
    data: function() {
        return dt;
    },
    props:  // as before...,

    template: `<div class="blog-post">
                    <h1>{{ post.title }}</h1>
                    <p>{{ post.body }}</p>
                    <div class="star-wrap">
                        <span v-for="n in 5"
                            class="star"
                            :class="{ full: hover >= n+1 }"
                            @click="stars = n+1"
                            @mouseover="hover = n+1"
                            @mouseout="hover = stars"
                        ></span>
                    </div>
               </div>`
});
در این حالت خروجی زیر را خواهیم داشت:



برای رفع این مشکل کافی است به اینصورت دیتا را تعریف کنیم:

Vue.component('blogPost', {
    data: function() {
        return {
             stars: 5,
             hover: 5
        }
    },
    props:  // as before...,
    template: // as before
});


تغییر دیتا درون کامپوننت‌ها

تا اینجا توانستیم از کامپوننت والد داده‌هایی را به کامپوننت‌های فرزند ارسال کنیم. اکنون می‌خواهیم قابلیت تغییر دیتای تعریف شده‌ی درون کامپوننت والد را درون کامپوننت‌ها نیز داشته باشیم:

Vue.component('child', {
    props: ['message'],
    methods: {
        changeName() {
            this.message = "New Name!..."
        }
    },
    template: '#child-template'
});

new Vue({
    el: '#app',
    data() {
        return {
            name: 'DNT!'
        }
    }
});

تمپلیت کامپوننت فوق نیز به صورت x-template درون DOM تعریف شده است:

<script type="text/x-template" id="child-template">
    <div>
        <p>{{ message }}</p>
        <button @click="changeName">Change Name</button>
    </div>
</script>


فراخوانی کامپوننت نیز به اینصورت می‌باشد:

<div id="app">
    <child :message="name"></child>
</div>

همانطور که مشاهده می‌کنید، دیتای name را از طریق ویژگی message توانسته‌ایم به کامپوننت child ارسال کنیم. درون تمپلیت آن نیز یک دکمه را برای تغییر مقدار این ویژگی تعریف کرده‌ایم. تغییر این ویژگی نیز یک assignment ساده است. اما اگر بر روی دکمه‌ی Change Name کلیک کنید، هشدار زیر را درون کنسول مشاهده خواهید کرد:

[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "message"

found in

---> <Child>
       <Root>

دلیل آن نیز مشخص است؛ زیرا با تغییر این ویژگی، کامپوننت والد از وجود تغییرات مطلع نشده‌است و فقط این تغییرات، درون کامپوننت child صورت گرفته‌است. برای اطلاع‌رسانی کامپوننت والد می‌توانیم از یک ایونت ویژه استفاده کنیم و کامپوننت والد را از وجود تغییرات مطلع کنیم:

changeName() {
    this.message = "New Name!...",
    this.$emit("change-name", this.message);
}

برای تگ child نیز این ایونت را اضافه خواهیم کرد:

<child :message="name" @change-name="name = $event"></child>

در اینحالت با تغییر ویژگی message، مقدار دیتای name نیز بلافاصله تغییر پیدا خواهد کرد.


Slots

Slot یک روش عالی برای جایگزینی محتوای درون یک کامپوننت است. فرض کنید می‌خواهیم کامپوننت‌مان به صورت زیر باشد:

<modal>
    Hello
</modal>

در اینحالت باید درون تمپلیت مکان قرارگیری Hello را تعیین کنیم. اینکار را می‌توانیم با قرار دادن تگ slot انجام دهیم:

Vue.component('modal', {
    template: `
            ...
            <div class="modal-body">
                <slot></slot>
            </div>
            ...
    `
});

اکنون هر محتوایی که درون تگ modal قرار گیرد، در قسمت slot نمایش داده خواهد شد. این نوع slot به صورت پیش‌فرض می‌باشد. در واقع می‌توانیم slotها را نیز نامگذاری کنیم. به عنوان مثال یک slot برای عنوان modal، یک slot برای بدنه modal و یک slot دیگر برای فوتر modal تعریف کنیم:

Vue.component('modal', {
    template: `
    <div class="modal fade" id="detailsModal" tabindex="-1" role="dialog" aria-labelledby="detailsModalLabel" aria-hidden="false">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="detailsModalLabel">
                        <slot name="title"></slot>
                    </h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <slot name="body"></slot>
                </div>
                <div class="modal-footer">
                    <slot name="footer"></slot>
                </div>
            </div>
        </div>
        </div>
    `
});

اکنون می‌توانیم محتوای مورد نظر را برای قرارگیری درون slotها تعیین کنیم:

<modal>
    <template slot="title">Title</template>
    <template slot="body">Lorem ipsum dolor sit amet.</template>
    <template slot="footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
    </template>
</modal>


مطالب
فرم‌های مبتنی بر قالب‌ها در Angular - قسمت چهارم - اعتبارسنجی ورودی‌ها
پس از برقراری ارتباط بین فرم و مدل آن در قسمت قبل، مرحله‌ی بعدی طراحی یک فرم خوب، اعتبارسنجی ورودی‌های کاربران است و واکنش نشان دادن به ورودی‌های نامطلوب.


کلاس‌های CSS اعتبارسنجی در Angular

زمانیکه Angular فرمی را تحت نظر قرار می‌دهد، کلاس‌های CSS خاصی را نیز بر اساس حالات عناصر مختلف آن، به آن‌ها متصل خواهد کرد. بر این اساس می‌توان ظاهر این المان‌ها را سفارشی سازی نمود. این کلاس‌ها به شرح زیر هستند:

  کلاس CSS اعتبارسنجی  توضیحات 
  ng-untouched   زمانیکه فرمی برای بار اول رندر می‌شود، تمام فیلدهای آن با کلاس CSS ایی به نام ng-untouched علامتگذاری می‌شوند. 
  ng-touched   همینقدر که کاربر با یک Tab از فیلدی عبور کند، با کلاس ng-touched مزین خواهد شد. بنابراین مهم نیست که حتما داده‌ای وارد شده باشد یا خیر. حتی عبور از یک فیلد نیز به معنای لمس آن نیز می‌باشد. 
 ng-pristine   مربوط به زمانی‌‌است که یک فیلد نه تغییر کرده‌است و نه لمس شده‌است. 
  ng-dirty   همینقدر که کاربر، تغییری را در فیلدی ایجاد کند، آن المان با کلاس ng-dirty مشخص خواهد شد. 
 ng-valid   برای حالت موفقیت آمیز بودن اعتبارسنجی، به آن المان انتساب داده می‌شود. 
  ng-invalid   برای حالت غیر موفقیت آمیز بودن اعتبارسنجی، به آن المان انتساب داده می‌شود. 

برای اینکه بتوانیم این موارد را در عمل مشاهده کنیم، به ابتدای فرم مثال این سری، تغییرات ذیل را اعمال خواهیم کرد:
<div class="form-group">
    <label>First Name</label>
    <input #firstName required type="text" class="form-control" name="firstName" [(ngModel)]="model.firstName">
</div>

<h3>Classes</h3>
<h4>{{ firstName.className }}</h4>
برای اینکه مشخص کنیم چه کلاسی به المان firstName متصل شده‌است، ابتدا نیاز است یک template reference variable را برای آن تعریف کنیم که اینکار را توسط معرفی firstName# انجام داده‌ایم. به این ترتیب است که می‌توان به خاصیت className آن در ادامه دسترسی یافت.


تصویر فوق کلاس‌هایی را نمایش می‌دهد که در اولین بار نمایش فرم، به المان firstName متصل شده‌اند. برای مثال در این حالت کلاس ng-pristine قابل مشاهده‌است و هنوز تغییری در آن حاصل نشده‌است.
در ادامه اگر حرفی را به آن اضافه کنیم:


هنوز هم ng-untouched آن برقرار است؛ اما ng-pristine آن به ng-dirty تبدیل شده‌است. در اینجا حتی اگر کل اطلاعات فیلد را نیز حذف کنیم و آن‌را خالی کنیم یا به حالت اول بازگردانیم نیز کلاس ng-dirty قابل مشاهده‌است. بنابراین اگر حالت فیلدی dirty شد، همواره به همین حالت باقی می‌ماند.
در این لحظه اگر با Tab به فیلد دیگری در فرم مراجعه کنیم:


در اینجا است که کلاس ng-untouched به ng-touched تبدیل می‌شود. بنابراین کلاس‌های مختلف لمس یک فیلد، ارتباطی به افزوده شدن یا حذف کاراکتری از یک فیلد ندارند و فقط به از دست رفتن focus و مراجعه‌ی به فیلد دیگری مرتبط می‌شوند.

اگر به المان تغییر یافته‌ی فوق دقت کنید، ویژگی required نیز به آن اضافه شده‌است (علاوه بر template reference variable ایی که تعریف کردیم). در این حالت کل فیلد را خالی کنید:


همانطور که مشاهده می‌کنید، اکنون کلاس ng-valid به کلاس ng-invalid تغییر یافته‌است.


ارتباط بین کلاس‌های CSS اعتبارسنجی و خواص ngModel

تمام کلاس‌های -ng ایی که در بالا معرفی شدند، معادل‌های خواص ngModel ایی نیز دارند. فقط کافی است -ng آن‌ها را حذف کنید، باقیمانده‌ی آن، نام خاصیت متناظری در ngModel خواهد بود. برای مثال کلاس ng-untouched به خاصیت untouched نگاشت می‌شود و به همین ترتیب برای مابقی.
template reference variable ایی را که تا به اینجا به المان اضافه کردیم (firstName#) به خواص همان المان دسترسی دارد (مانند className آن). اما در ادامه می‌خواهیم این متغیر به ngModel و خواص آن دسترسی داشته باشد و میدان دید آن تغییر کند. به همین جهت تنها کافی است تا ngModel را به این متغیر انتساب دهیم:
<div class="form-group">
    <label>First Name</label>
    <input #firstName="ngModel" required type="text" class="form-control" name="firstName" [(ngModel)]="model.firstName">
</div>

<h4>dirty: {{ firstName.dirty }}</h4>
پس از این تغییر اکنون template reference variable تعریف شده می‌تواند برای نمونه به خاصیت dirty شیء ngModel دسترسی پیدا کند.


یک نکته: در حالت خواص valid و invalid که مرتبط با اعتبارسنجی هستند، خاصیت سومی نیز به نام errors وجود دارد که حاوی اطلاعات بیشتری در مورد خطای اعتبارسنجی رخ داده‌است. بنابراین وجود این خاصیت و نال نبودن آن نیز دلالت بر وجود یک خطای اعتبارسنجی است. از خاصیت errors در ادامه‌ی بحث در قسمت «مدیریت چندین خطای همزمان اعتبارسنجی» استفاده خواهیم کرد.


نمایش بهتر خطاهای اعتبارسنجی با بررسی خواص ngModel

یکی از مزایای کار با خواص ngModel، امکان استفاده‌ی از آن‌ها در عبارات شرطی‌است که نسبت به کلاس‌های CSS معرفی شده‌ی در ابتدای بحث، انعطاف پذیری بیشتری را به همراه خواهند داشت.
<div class="form-group">
    <label>First Name</label>
    <input #firstName="ngModel" #firstNameElement required type="text" class="form-control" 
              name="firstName" [(ngModel)]="model.firstName">
    <div *ngIf="firstName.invalid && firstName.touched" class="alert alert-danger">
        First Name is required.
    </div>      
</div>

<h4>className: {{ firstNameElement.className }}</h4>
<h4>dirty: {{ firstName.dirty }}</h4>
<h4>invalid: {{ firstName.invalid }}</h4>
توسط ngIf می‌توان المانی را به DOM اضافه و یا کلا از آن حذف کرد. در اینجا یک عبارت boolean به آن نسبت داده شده‌است. ابتدا حالت firstName.invalid را بررسی کنید. مشاهده خواهید کرد که اگر فرم برای بار اول و با مقادیر خالی نمایش داده شود، div خطا نیز ظاهر می‌شود که آنچنان خوشایند نیست و بهتر است خطاها را پس از اینکه کاربر مشغول به کار با فرم شد، به او نمایش دهیم؛ تا اینکه از همان ابتدا این خطاها به صورت واضحی نمایش داده شوند. بنابراین && firstName.touched نیز در اینجا اضافه شده‌است. به این ترتیب div نمایش دهنده‌ی alert بوت استرپ، دیگر در اولین بار نمایش یک فرم خالی، ظاهر نخواهد شد. اما اگر کاربر با یک tab از فیلدی خالی رد شد، آنگاه این خطا نمایش داده می‌شود.



نمایش بهتر خطاهای اعتبارسنجی با مزین ساختن المان‌های ورودی

علاوه بر نمایش یک alert بوت استرپی متناظر با یک فیلد غیرمعتبر، می‌توان خود المان‌های ورودی را نیز با شیوه‌نامه‌هایی مزین ساخت.


این کار را در بوت استرپ با افزودن کلاس has-error در کنار form-group انجام می‌دهند. همچنین label نیز باید به کلاس control-label مزین شود تا hass-error بر روی آن نیز تاثیرگذار شود. برای پیاده سازی پویای آن در Angular به روش ذیل عمل می‌شود:
<div class="form-group" [class.has-error]="firstName.invalid && firstName.touched">
   <label class="control-label">First Name</label>
در اینجا روش افزودن شرطی کلاس ویژه‌ی has-error بوت استرپ را به مجموعه کلاس‌های div جاری ملاحظه می‌کنید. هر زمان که شرط ذکر شده برقرار باشد، در عبارت property binding مخصوص class.className، این className را به صورت خودکار به مجموعه کلاس‌های آن المان اضافه می‌کند و برعکس.
بنابراین اگر المان firstName خالی باشد و همچنین با یک Tab از روی آن عبور کرده باشیم، کلاس has-error در کنار کلاس form-group اضافه می‌شود.

روش دوم: همانطور که در ابتدای بحث نیز عنوان شد، Angular بر اساس حالات مختلف یک فیلد، کلاس‌های CSS خاصی را به آن‌ها انتساب می‌دهد. یک چنین کاری را با مقدار دهی این کلاس‌ها در فایل src\styles.css نیز می‌توان انجام داد که دقیقا معادل بررسی خواص invalid و touched با کدنویسی است:
.ng-touched.ng-invalid{
    border: 1px solid red;
}


سایر ویژگی‌های اعتبارسنجی HTML 5

تا اینجا ویژگی استاندارد required را به المان ورودی فرم ثبت اطلاعات کاربران، اضافه کردیم.
<input #firstName="ngModel" #firstNameElement 
required maxlength="3" minlength="2" pattern="^V.*"
type="text" class="form-control" name="firstName" [(ngModel)]="model.firstName">
در اینجا برای مثال اعمال ویژگی‌های maxlength، minlength و pattern را مشاهده می‌کنید. ویژگی pattern برای تعریف عبارات باقاعده بکار می‌رود (برای مثال، نام حتما باید با V شروع شود) و تقریبا در تمام مرورگرها (caniuse.com ) نیز پشتیبانی می‌شود.
برای نمونه minlength همه‌جا پشتیبانی نمی‌شود؛ اما آن‌را می‌توان برای مثال با الگویی مساوی "+..." جایگزین کرد.


مشکل! ذکر چند ویژگی اعتبارسنجی با هم، تداخل ایجاد می‌کنند!

در اینجا چون چهار ویژگی مختلف را به صورت یکجا به یک المان متصل کرده‌ایم، اکنون div ذیل به هر کدام از این ویژگی‌ها به صورت یکسانی واکنش نشان خواهد داد؛ زیرا خاصیت invalid را true می‌کنند:
    <div *ngIf="firstName.invalid && firstName.touched" class="alert alert-danger">
        First Name is required.
    </div>
روش مدیریت این حالت، به صورت ذیل است:
    <div class="form-group" [class.has-error]="firstName.invalid && firstName.touched">
      <label class="control-label">First Name</label>
      <input #firstName="ngModel" #firstNameElement 
             required maxlength="3" minlength="2" pattern="^V.*"
             type="text" class="form-control" name="firstName" [(ngModel)]="model.firstName">
      <div *ngIf="firstName.invalid && firstName.touched">
        <div class="alert alert-info">
           errors: {{ firstName.errors | json }}
        </div> 
        <div class="alert alert-danger" *ngIf="firstName.errors.required">
           Name is required.
        </div>
        <div class="alert alert-danger" *ngIf="firstName.errors.minlength">
           Name should be minimum {{firstName.errors.minlength.requiredLength}} characters.
        </div>
        <div class="alert alert-danger" *ngIf="firstName.errors.maxlength">
           Name should be max {{firstName.errors.maxlength.requiredLength}} characters.
        </div>
        <div class="alert alert-danger" *ngIf="firstName.errors.pattern">
           Name pattern: {{firstName.errors.pattern.requiredPattern}}
        </div>
      </div>      
    </div>
با یک چنین خروجی:


همانطور که در تصویر ملاحظه می‌کنید، محتوای خاصیت errors به صورت JSON، جهت دیباگ نیز درج شده‌است.
بنابراین وجود خاصیت firstName.errors.minlength و یا firstName.errors.pattern به این معنا است که این خطاهای خاص وجود دارند (خاصیت firstName.errors به همراه اضافاتی است) و برعکس نال بودن آن‌ها مؤید عدم وجود خطایی است. به همین جهت می‌توان به ازای هر کدام، یک div جداگانه را تشکیل داد.
مرحله‌ی بعد، استخراج اطلاعات بیشتری از همین شیء و محتوای خاصیت errors است. برای مثال زمانیکه در آن خاصیت minlength ظاهر شد، این خاصیت نیز دارای خاصیتی مانند requiredLength است که از آن می‌توان جهت درج عدد واقعی مورد نیاز این اعتبارسنج استفاده کرد.


بهبود اعتبارسنجی drop down

در حالت فعلی تعریف drop down مثال این سری، نیازی به اعتبارسنجی نیست؛ چون لیست مشخصی از طریق کامپوننت در اختیار این المان قرار می‌گیرد و همواره دقیقا یکی از این عناصر انتخاب خواهند شد. اما اگر گزینه‌ی دیگری را مانند:
<option value="default">Select a Language...</option>
به ابتدای این لیست اضافه کنیم، اینبار نیاز به اعتبارسنجی خواهد بود؛ زیرا اکنون کاربر می‌تواند گزینه‌ای را انتخاب نکند و راهی پیش فرض هم برای اعتبارسنجی این گزینه وجود ندارد.
    <div class="form-group" [class.has-error]="hasPrimaryLanguageError">
      <label class="control-label">Primary Language</label>
      <select class="form-control" name="primaryLanguage" 
                #primaryLanguage
                (blur)="validatePrimaryLanguage(primaryLanguage.value)"
                (change)="validatePrimaryLanguage(primaryLanguage.value)"
                [(ngModel)]="model.primaryLanguage">
          <option value="default">Select a Language...</option>
          <option *ngFor="let lang of languages">
            {{ lang }}
          </option>
      </select>
    </div>
در اینجا اتصال به class.has-error را همانند مثال‌های قبلی مشاهده می‌کنید. اما اینبار به یک خاصیت عمومی تعریف شده‌ی در سطح کامپوننت متصل شده‌است؛ زیرا Angular در مورد این المان خاص، کاری را برای ما انجام نخواهد داد. همچنین پیاده سازی حالت عبور از این کامپوننت با Tab نیز توسط اتصال به رخداد blur صورت گرفته‌است تا هر زمانیکه این فیلد focus را از دست داد، اجرا شود. دسترسی به مقدار جاری انتخابی این select نیز توسط یک template reference variable به نام primaryLanguage# صورت گرفته‌است. به این ترتیب می‌توان به خواص این المان مانند value آن دسترسی پیدا کرد. همچنین چون می‌خواهیم با انتخاب گزینه‌ی دیگری این علامت خطا رفع شود، این متد به رخداد change نیز علاوه بر blur، متصل شده‌است.
export class EmployeeRegisterComponent {
  hasPrimaryLanguageError = false;

  validatePrimaryLanguage(value) {
    if (value === 'default'){
      this.hasPrimaryLanguageError = true;
      }
    else{
      this.hasPrimaryLanguageError = false;
      }
  }
}
کار این متد تغییر مقدار hasPrimaryLanguageError است تا کلاس has-error در فرم نمایش داده شود. در اینجا اگر مقدار primaryLanguage انتخابی همان گزینه‌ی default ابتدایی باشد، خاصیت hasPrimaryLanguageError به true تنظیم می‌شود:



اعتبارسنجی در سطح کل فرم

تا اینجا بررسی‌هایی را که انجام دادیم، در سطح فیلدها بودند. اکنون اگر کاربر به طور کامل تمام این فیلدها را تغییر ندهد و بر روی دکمه‌ی ارسال کلیک کند چطور؟
<form #form="ngForm" novalidate>
زمانیکه فرم جاری را ایجاد کردیم، یک template reference variable را به نام form# نیز به آن نسبت دادیم و چون به ngForm متصل شده‌است، می‌توان به خواص این شیء نیز دسترسی یافت. برای نمونه پس از دکمه‌ی ثبت، عبارت ذیل را تعریف کنید:
<h3> form.valid: {{ form.valid }}</h3>
همانطور که ملاحظه می‌کنید یکی از خواص شیء ngForm که توسط متغیر form قابل دسترسی شده‌است، خاصیت valid می‌باشد که حاصل اعتبارسنجی تمام عناصر داخل فرم است. برای مثال می‌توان از این خاصیت جهت فعال یا غیرفعال کردن دکمه‌ی ثبت اطلاعات نیز استفاده کرد:
<button class="btn btn-primary" type="submit"
            [disabled]="form.invalid">Ok</button>
در اینجا مقدار form.invalid به خاصیت disabled المان متصل شده‌است و اگر اعتبارسنجی فرم با شکست مواجه شود، این دکمه در حالت غیرفعال ظاهر می‌شود.


در قسمت بعد نحوه‌ی ارسال این فرم را به سرور، بررسی می‌کنیم.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: angular-template-driven-forms-lab-04.zip
برای اجرای آن فرض بر این است که پیشتر Angular CLI را نصب کرده‌اید. سپس از طریق خط فرمان به ریشه‌ی پروژه وارد شده و دستور npm install را صادر کنید تا وابستگی‌های آن دریافت و نصب شوند. در آخر با اجرای دستور ng serve -o برنامه ساخته شده و در مرورگر پیش فرض سیستم نمایش داده خواهد شد.
مطالب
ایجاد alert,confirm,prompt هایی متفاوت با jQuery Impromptu
alert,confirm,prompt سه متد توکار JavaScript هستند که برای نمایش پیغام ، دریافت تایید و دریافت مقدار از کاربر هستند .
گرافیک این پیغام‌ها هم وابسته به مرورگر هستند و قابل تغییر نیستند . متن عنوان و دکمه‌ها هم با توجه به زبان سیستم عامل تعیین می‌شوند و قابل تغییر توسط برنامه نویس نیستند.



حال مواقعی پیش می‌آید که نیاز داریم پیغام هایی با گرافیک و عبارات متفاوت نمایش دهیم . برای رفع این نیاز می‌توانیم از پلاگین jQuery Impromptu استفاده کنیم . البته این پلاگین قابلیت‌های دیگری هم دارد که در این مقاله با آنها آشنا می‌شویم .




از ویژگی‌های این پلاگین می‌توان حجم کم (حدود 11 کیلوبایت) و قدرت شخصی سازی بالا اشاره کرد .

طرز استفاده به این شکل است :

$.prompt( msg , options )


msg می‌تواند یک string یا یک شئ از states باشد . string ارسال شده می‌تواند شامل کدهای html باشد .

یک شئ states هم شامل مجموعه ای از وضعیت‌های prompt است . برای مثال می‌توان یک prompt ایجاد کرد که مثل یک Wizard شامل چند مرحله باشد .

options هم تنظیماتی است که می‌توان مشخص کرد . تنظیماتی مثل : prefix,classes,persistent,timeout,...


msg :


گفتیم شئ states شامل وضعیت‌های مختلف prompt است . هر وضعیت ( state ) می‌تواند شامل بخش‌های زیر باشد :

  • html : مقدار Html وضعیت

  • buttons : یک شئ شامل متن و مقدار دکمه هایی که کاربر می‌تواند کلیک کند

  • focus : ایندکس دکمه‌ی focus شده در وضعیت

  • submit : تابعی که زمانی که یکی از دکمه‌های وضعیت انتخاب شود فراخوانی می‌شود .

    اگر در این تابع false بازگشت داده شود یا متد preventDefault از event فراخوانی شود ، prompt باز می‌ماند . ( روشی برای جلوگیری از بسته شدن prompt هنگام تغییر state یا اعتبار سنجی فرم )
    همچنین شئ event شامل state ( المنت state ) و stateName ( نام state ) می‌باشد .

    پیشفرض :
    function(event, value, message, formVals){}
    value مقدار دکمه ای است که بروی آن کلیک شده ، message مقدار html تعریف شده برای state است ، formVals هم در صورتی که در html تعریف شده برای state ، المنت‌های فرم وجود داشته باشد ، شامل نام/مقادیر آنها می‌باشد . ( برای دریافت مقادیر فرم ، باید از نام المنت استفاده نمایید . )

  • position : مشخص کننده‌ی موقعیت state که شامل موارد زیر است :

    position: { container: '#container', x: 0, y: 0, width: 0, arrow: 'lm' }

    container : ‫selector المنتی است که state باید در آن مکان قرار بگیرد .
    x/y : موقعیت نسبی prompt نسبت به container
    arrow : جهت نمایش فلش prompt است که می‌تواند یکی از این مقادیر باشد : tl, tc, tr, rt, tm, tb, br, bc, bl, lb, lm, lt.



نحوه تعریف یک wizard ساده با شئ states :
var tourSubmitFunc = function (e, v, m, f) {
    if (v === -1) {
        $.prompt.prevState();
        return false;
    } else if (v === 1) {
        $.prompt.nextState();
        return false;
    }
};

var states =
    {
        state0:
            {
                html: "State1",
                buttons: { Next: 1 },
                //position: { container: '#container', x: 10, y: 0, width: 350, arrow: 'lm' },
                submit: tourSubmitFunc
            },
        state1:
            {
                html: "State2",
                buttons: { Prev: -1, Next: 1 },
                submit: tourSubmitFunc
            },
        state2:
            {
                html: "State3",
                buttons: { Prev: -1, Done: 0 },
                submit: tourSubmitFunc
            }
    };

$.prompt(states);


تا به اینجا با پارامتر اول prompt آشنا شدیم و فهمیدیم که می‌توانیم یک رشته یا یک شئ states به عنوان message به prompt ارسال کنیم .

options :

اکنون با optionهای prompt ( پارامتر دوم ) آشنا خواهیم شد .

توجه کنید که زمانی که یک رشته به prompt ارسال کنید ، مقادیر buttons,focus,submit از این تنظیمات دریافت می‌شود .
به عبارت دیگر ، زمانی که یک شئ states به prompt ارسال کنید ، از مقادیر فوق که در تنظیمات است ، استفاده نمی‌شود .


  • loaded
    یک تابع که زمانی که prompt کامل بارگزاری شده فراخوانی می‌شود .
    $.prompt("Message",
        {
            loaded: function() {
                alert("Prompt Loaded !");
            }
        });
  • submit
    یک تابع که زمانی که یکی از دکمه‌های state کلیک شود ، فراخوانی می‌شود .
    ( زمانی اتفاق میوفتد که یک رشته به عنوان متن به prompt  ارسال کرده باشید و زمانی که یک شئ از states ارسال می‌کنید ، هنگام کلیک دکمه‌های آنها ، این تابع فراخوانی نمی‌شود . )
    پیشفرض :
    function(event){}
  • statechanging
    یک تابع که زمانی که یک state در حال تعویض شدن هست فراخوانی می‌شود .
    پیشفرض :
    function(event, fromStateName, toStateName){}
    برای لغو تغییر state ، مقدار return false کنید یا متد preventDefault از event را فراخوانی کنید .

  • statechanged
    یک تابع که زمانی که یک state در حال تعویض شدن هست فراخوانی می‌شود .
    پیشفرض :
    function(event, toStateName){}
  • callback
    یک تابع که زمانی که ( یکی از دکمه‌های prompt کلیک شود و ) prompt بسته شود ، فراخوانی می‌شود .
    پیشفرض :
    function(event[, value, message, formVals]){}
    سه پارامتر آخر تنها زمانی که یک دکمه‌ی prompt کلیک شده باشد موجود هستند .

  • buttons
    یک شئ شامل مجموعه ای از دکمه‌ها .
    پیشفرض :
    { Ok : true }
    شکل دیگر تعریف دکمه به این شکل است :
    [
        {title: 'Hello World',value:true},
        {title: 'Good Bye',value:false}
    ]
  • prefix
    یک پیشوند برای همه css class‌ها و id‌های المنت‌های html که توسط prompt ایجاد می‌شود .
    پیشفرض : jqi

  • classes
    یک css class که به بالاترین سطح prompt داده می‌شود .
    در حالت پیشفرض مقداری ندارد .

  • focus
    ایندکس دکمه‌ی focus شده
    پیشفرض : 0

  • zIndex
    zIndex اعمال شده بروی prompt .
    پیشفرض : 999

  • useiframe
    استفاده از یک iframe برای overlay در IE6
    پیشفرض : false

  • top
    فاصله‌ی prompt از بالای صفحه
    پیشفرض : ‭15%

  • opacity
    میزان شفافیت لایه‌ی ای که صفحه را پوشانده است .
    پیشفرض : 0.6

  • overlayspeed
    سرعت نمایش افکت fadeIn , fadeOut لایه‌ی پوشاننده .
    مقادیر قابل قبول : ‭"slow", "fast", number(milliseconds)
    پیشفرض : "slow"

  • promptspeed
    سرعت نمایش prompt .
    مقادیر قابل قبول : ‭"slow", "fast", number(milliseconds)
    پیشفرض : "fast"

  • show
    نام یک متد jQuery برای animate کردن نمایش prompt .
    مقادیر قابل قبول : "show","fadeIn","slideDown", ...
    پیشفرض : "promptDropIn"

  • persistent
    بسته شدن prompt زمانی که بروی لایه‌ی fade کلیک شود .
    false : بسته شدن
    پیشفرض : true

  • timeout
    مدت زمانی که پس از آن ، prompt بصورت خودکار بسته می‌شود . ( milliseconds )
    پیشفرض : 0


returns
:

مقدار بازگشتی متد prompt ، یک شئ jQuery ، شامل همه‌ی محتویات تولید شده توسط prompt است .


Events using Bind
:
استفاده از Eventها با بایند کردن

  • promptloaded
    معادل loaded در optionها .

  • promptsubmit
    هنگام submit شدن ( کلیک شدن یکی از دکمه‌های ) state فعال می‌شود .

  • promptclose
    معادل callback در optionها .

  • promptstatechanging
    معادل statechanging در optionها .

  • promptstatechanged
    معادل statechanged در optionها .

ظرز بایند کردن یک event به شئ prompt :
var myPrompt = $.prompt( msg , options );
myPrompt.bind('promptloaded', function(e){});


Helper Functions :

  • ‪jQuery.prompt.setDefaults(options)
    تعیین مقادیر پیشفرض برای همه‌ی prompt‌ها .
    jQuery.prompt.setDefaults({
    prefix: 'myPrompt',
    show: 'slideDown'
    });
  • ‪jQuery.prompt.setStateDefaults(options)
    تعیین مقادیر پیشفرض برای stateها .
    jQuery.prompt.setStateDefaults({
    buttons: { Ok:true, Cancel:false },
    focus: 1
    });
  • ‪jQuery.prompt.getCurrentState()
    یک شئ jQuery از state جاری برمی‌گرداند .

  • ‪jQuery.prompt.getCurrentStateName()
    نام state جاری را برمی‌گرداند .

  • ‪jQuery.prompt.getStateContent(stateName)
    یک شئ jQuery از state مشخص شده برمی‌گرداند .

  • ‪jQuery.prompt.goToState(stateName, callback)
    state مشخص شده را در prompt نمایش می‌دهد .
    callback تابعی است که بعد از تغییر state فراخوانی می‌شود .

  • ‪jQuery.prompt.nextState(callback)
    prompt را به state بعدی منتقل می‌کند .

  • ‪jQuery.prompt.prevState(callback)
    prompt را به state قبلی منتقل می‌کند .

  • ‪jQuery.prompt.close()
    prompt را می‌بندد .


حال که با این پلاگین آشنا شدیم ، سه دستور جاوا اسکریپتی که در ابتدای مقاله ذکر کردیم را با این پلاگین پیاده سازی می‌کنیم .

  • alert
    $.prompt("یک پیام تستی",
        {
            prefix: 'dnt',
            buttons: { 'تایید': true }
        });

    نتیجه :



  • confirm
    $.prompt("درخواست تایید - موافقید ؟",
        {
            prefix: 'dnt',
            buttons: { 'تایید': true, 'انصراف': false }
        });

    نتیجه :



  • prompt
    یک فرم html مخفی برای نمایش در prompt :

    <div class="prompt-content" style="display: none;">
        <span>نام خود را وارد نمایید : </span>
        <span>
            <input type="text" name="name" />
        </span>
    </div>

       
    نمایش prompt :

    $.prompt(
        $(".prompt-content").html(),
        {
            prefix: 'dnt',
            buttons: { 'تایید': true, 'انصراف': false }
        });

    نتیجه :



در این سه مثال آخر ، از یک css متفاوت استفاده کردیم . این پلاگین یک سری کلاس دارد که نام این کلاس‌ها از ترکیب مقدار prefix که در option مشخص کردیم حاصل می‌شود .
برای مثال اگر مقدار prefix را برابر با dnt قرار بدهیم ، برای استایل دهی متن پیام باید از کلاس div.dnt .dntmessage استفاده کنید .
همانطور که در سه مثال آخر مشاهده کردید ، تغییری در استایل prompt داشتیم که با تغییر دادن استایل‌های مورد نظر انجام شد .
برای تهیه‌ی یک قالب سفارشی باید selector المنت هایی که نیاز به تغییر دارند را از قالب پیشفرض پیدا کنید ، سپس قسمت prefix از selector را به نام قالب خودتان تغییر بدید و استایل را ویرایش کنید . سپس هنگام ایجاد prompt ، مقدار prefix را برابر نام قالب قرار دهید .

مثلا می‌خواهید یک قالب به نام dnt داشته باشید . می‌خواهید متن قالب راست به چپ باشد .

div.dnt .dntmessage {
     color: #444444;
     line-height: 20px;
     padding: 10px;
/*       Edited      */
     direction:rtl;
     text-align:right;
}


البته راه بهتری هم هست که نیاز به آشنایی با فایرباگ دارد . در این روش ابتدا کل قالب jqi ( موجود در قالب پیشفرض ) را در برنامه خود کپی می‌کنیم ، مقادیر jqi را با نام قالب جایگزین می‌کنیم ، مقدار prefix را در prompt برابر با نام قالب قرار می‌هیم .
اکنون در FireFox یک prompt ایجاد می‌کنیم و توسط فایرباگ استایل هایی که با نام قالب بروی prompt اعمال شده‌اند را مطابق سلیقه تغییر می‌دهیم . در مرحله آخر به تب CSS در فایرباگ می‌رویم و کل استایل‌های مربوط به قالب را کپی و جایگزین استایل قبلی در برنامه می‌کنیم .

قالبی که بنده برای سه دستور فوق استفاده کردم ( dnt ) ، به این شکل است :
/*    Start : DotNetTips Theme     */

.dntfade {
     background-color: #AAAAAA;
     position: absolute;
}

div.dnt {
     background-color: #FFFFFF;
     border-radius: 10px 10px 10px 10px;
     border: 1px solid #FFFFFF;
     box-shadow: 0px 0px 10px 1px #6D6D6C;
     font-family: tahoma;
     font-size: 11px;
     padding: 7px;
     position: absolute;
     text-align: left;
     width: 400px;
}

div.dnt .dntcontainer {
     font-size: small;
}

div.dnt .dntclose {
     color: #BBBBBB;
     cursor: pointer;
     font-weight: bold;
     position: absolute;
     top: 4px;
     width: 18px;
}

div.dnt .dntmessage {
     color: #444444;
     line-height: 20px;
     padding: 10px;
}

div.dnt .dntbuttons {
     background-color: #F4F4F4;
     border: 1px solid #EEEEEE;
     padding: 5px 0px;
     text-align: right;
}

div.dnt button {
     background-color: #2F6073;
     border: 1px solid #F4F4F4;
     color: #FFFFFF;
     font-size: 12px;
     font-weight: bold;
     margin: 0px 10px;
     padding: 3px 10px;
}

div.dnt button:hover {
     background-color: #728A8C;
}

div.dnt button.dntdefaultbutton {
     background-color: #0099CC;
}

.dnt_state {
     direction: rtl;
     text-align: right;
}

.dnt_state button {
     font-family: tahoma;
}

.dntwarning .dnt .dntbuttons {
     background-color: #CCDDFF;
}

.dnt .dntarrow {
     border: 10px solid transparent;
     font-size: 0px;
     height: 0px;
     line-height: 0;
     position: absolute;
     width: 0px;
}

.dnt .dntarrowtl {
     border-bottom-color: #FFFFFF;
     left: 10px;
     top: -20px;
}

.dnt .dntarrowtc {
     border-bottom-color: #FFFFFF;
     left: 50%;
     margin-left: -10px;
     top: -20px;
}

.dnt .dntarrowtr {
     border-bottom-color: #FFFFFF;
     right: 10px;
     top: -20px;
}

.dnt .dntarrowbl {
     border-top-color: #FFFFFF;
     bottom: -20px;
     left: 10px;
}

.dnt .dntarrowbc {
     border-top-color: #FFFFFF;
     bottom: -20px;
     left: 50%;
     margin-left: -10px;
}

.dnt .dntarrowbr {
     border-top-color: #FFFFFF;
     bottom: -20px;
     right: 10px;
}

.dnt .dntarrowlt {
     border-right-color: #FFFFFF;
     left: -20px;
     top: 10px;
}

.dnt .dntarrowlm {
     border-right-color: #FFFFFF;
     left: -20px;
     margin-top: -10px;
     top: 50%;
}

.dnt .dntarrowlb {
     border-right-color: #FFFFFF;
     bottom: 10px;
     left: -20px;
}

.dnt .dntarrowrt {
     border-left-color: #FFFFFF;
     right: -20px;
     top: 10px;
}

.dnt .dntarrowrm {
     border-left-color: #FFFFFF;
     margin-top: -10px;
     right: -20px;
     top: 50%;
}

.dnt .dntarrowrb {
     border-left-color: #FFFFFF;
     bottom: 10px;
     right: -20px;
}

/*    End : DotNetTips Theme     */


برای مشاهده‌ی مثال‌های بیشتر به صفحه‌ی اصلی jQuery Impromptu مراجعه نمایید .
نظرات مطالب
ایجاد alert,confirm,prompt هایی متفاوت با jQuery Impromptu
سلام؛

طبق مطلب ارائه شده در مقاله:

تابع submit :
 function(event, value, message, formVals){}
value مقدار دکمه ای است که بروی آن کلیک شده ، message مقدار html تعریف شده برای state است ، formVals هم در صورتی که در html تعریف شده برای state ، المنت‌های فرم وجود داشته باشد ، شامل نام/مقادیر آنها می‌باشد . ( برای دریافت مقادیر فرم ، باید از نام المنت استفاده نمایید . )


خب حالا مشابه مثال زیر عمل کنید:
<div class="prompt-content" style="display: none;">
    <span>ایمیل خود را وارد نمایید : </span>
    <span>
        <input type="text" name="user_email" />
    </span>
</div>

$.prompt(
    $(".prompt-content").html(),
    {
        submit: function (e, v, m, f) {
            var userEmail = f["user_email"];
            console.log(userEmail);
        }
    });


مطالب دوره‌ها
نگاهی به اجزای سیستم راهبری بوت استرپ 3
در مطلب «نگاهی به اجزای تعاملی Twitter Bootstrap» مباحث سیستم راهبری بوت استرپ 2 بررسی شدند. در ادامه قصد داریم، نکات جدیدی را در اینباره خصوصا جهت ارتقاء به بوت استرپ 3، بررسی کنیم.


تعیین موقعیت کاربر در صفحه به کمک breadcrumbs در Bootstrap

در مورد قسمت breadcrumb، مطالب مانند قبل و پیشنیاز ذکر شده است. با این تفاوت که بهتر است بجای ul از ol استفاده شود؛ چون ترتیب این عناصر مهم است. ol به معنای ordered list می‌باشد:
            <ol class="breadcrumb">
                <li><a href="#">خانه</a></li>
                <li><a href="#">خدمات</a></li>
                <li class="active">محصولات</li>
            </ol>


یک سؤال: اگر نخواهیم این خطوط مورب ظاهر شوند و برای مثال علاقمند باشیم تا از گلیف آیکن‌های معرفی شده در قسمت قبل استفاده کنیم، چه باید کرد؟
برای این منظور نیاز است با نحوه رندر خطوط مورب در بوت استرپ آشنا شویم. بنابراین فایل bootstrap-rtl.css را گشوده و چند سطر ذیل را جستجو کنید:
.breadcrumb > li + li:before {
  content: "/\00a0";
  padding: 0 5px;
  color: #cccccc;
}
همانطور که ملاحظه می‌کنید، تفسیر عبارت ذکر شده در قسمت content سبب نمایش این خط مورب است. برای حذف آن، به فایل custom.css پروژه مراجعه و تعاریف ذیل را اضافه خواهیم کرد (این فایل همانطور که در قسمت اول ذکر شد، باید پس از ذکر لینک فایل CSS اصلی بوت استرپ، تعریف شود):
.breadcrumb > li + li:before {
  content: none;
}
به این ترتیب خطوط مورب breadcrumb حذف می‌شوند. اکنون برای افزودن گلیف آیکن‌ها به صورت زیر می‌توان عمل کرد:
            <ol class="breadcrumb">
                <li><a href="#">خانه</a> <span class="glyphicon glyphicon-circle-arrow-left"></span></li>
                <li><a href="#">خدمات</a> <span class="glyphicon glyphicon-circle-arrow-left"></span></li>
                <li class="active">محصولات</li>
            </ol>


اگر از رنگ گلیف آیکن‌‌های نمایش داده شده راضی نیستید، آن‌ها را نیز می‌توانید در فایل CSS سفارشی خود تغییر دهید. برای مثال:
.glyphicon {
color: #cdae51;
}



تعریف برگه‌ها در Twitter Bootstrap
در مورد تعریف برگه‌ها، بوت استرپ 3 با نگارش 2 آن، تفاوتی ندارد و تمام نکات مطلب «نگاهی به اجزای تعاملی Twitter Bootstrap» در اینجا نیز صادق هستند. یک ul باید تعریف شود و سپس برای نمونه کلاس‌های nav nav-tabs را به آن‌ها اضافه خواهیم کرد تا به شکل tab به نظر برسند. برگه فعال نیز با کلاس active مشخص می‌شود.
یک نکته جدید: در بوت استرپ 3 می‌توان یک برگه را کاملا در عرض صفحه کشید و امتداد داد:
                <ul class="nav nav-pills nav-justified">
                    <li><a href="#">Home</a></li>
                    <li><a href="#">About</a></li>
                    <li class="active"><a href="#">Services</a></li>
                    <li><a href="#">Photo Gallery</a></li>
                    <li><a href="#">Contact</a></li>
                </ul>
با اضافه کردن nav-justified، بجای شکل زیر


به تصویر ذیل خواهیم رسید که در آن tab، در امتداد صفحه کشیده شده است:




تعریف navbar در بوت استرپ 3

اصول کلی navbar بوت استرپ 3 همانند بوت استرپ 2 است؛ با چند تفاوت کوچک:
- کلاس btn-navbar بوت استرپ 2 به کلاس navbar-btn در بوت استرپ 3 تغییر نام یافته است.
- کلاس navbar-inner بوت استرپ 2 کلا حذف شده است.
- کلاس‌های nav-list به کلاس‌های list-group تغییر نام یافته‌اند.
- کلاس brand با navbar-brand جایگزین شده است.
- کلاس‌های navbar-brand و navbar-toggle باید داخل المانی با کلاس navbar-header محصور شوند.
- کلاس nav باید به همراه navbar-nav باشد.
- کلاس‌های جدید navbar-default  navbar-text  navbar-btn  navbar-header اضافه شده‌اند.

یک مثال:
    <div class="container">
        <h4 class="alert alert-info">
            nav</h4>
        <div class="row">
            <nav class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#collapse">
                        <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span><span
                            class="icon-bar"></span><span class="icon-bar"></span>
                    </button>
                </div>
                <div class="collapse navbar-collapse" id="collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="#">Home</a></li>
                        <li><a href="#">About</a></li>
                        <li class="active"><a href="#">Services</a></li>
                        <li><a href="#">Photo Gallery</a></li>
                        <li><a href="#">Contact</a></li>
                    </ul>
                </div>
            </nav>
        </div>
        <!-- end row -->
    </div>
    <!-- /container -->
به همراه CSS سفارشی:
 body { padding-top: 70px; }






توضیحات:
- CSS سفارشی، سبب خواهد شد تا تگ h4 بالای صفحه، زیر navbar مخفی نشده و قابل مشاهده باشد.
- کار با المان nav دارای کلاس navbar navbar-default شروع می‌شود. همچنین role=navigation نیز به این المان اضافه شده‌است. این مورد  کمکی خواهد بود به افرادی با قدرت بینایی کم که از screen readers استفاده می‌کنند.
- داخل navbar-default یک div دیگر با کلاس navbar-header اضافه شده است. این مورد قابلیت‌های واکنشگرای navbar را فراهم می‌سازد. به این ترتیب زمانیکه عرض صفحه کمتر می‌شود، مانند تصویر دوم، یک دکمه ویژه نمایش داده خواهد شد.
- هرجایی در بوت استرپ ویژگی‌های data- را ملاحظه کردید، یعنی قرار است اطلاعاتی در اختیار اجزای جاوا اسکریپتی آن قرار گیرند. برای نمونه data-target به یک div با آی دی مساوی collapse اشاره می‌کند. به این معنا که اگر در زمان کم بودن عرض صفحه، دکمه ویژه واکنشگرای navbar ظاهر شد، با کلیک بر روی آن دکمه، div یاد شده را نمایش بده.
- span تعریف شده با کلاس sr-only به معنای اطلاعاتی است که صرفا جهت screen readers تدارک دیده شده‌اند.


فایل‌های نهایی این قسمت را از اینجا نیز می‌توانید دریافت کنید:
bs3-sample03.zip
 
مطالب
React 16x - قسمت 9 - ترکیب کامپوننت‌ها - بخش 3 - Lifecycle Hooks
کامپوننت‌ها در طول چرخه‌ی عمر خود، از چندین مرحله عبور می‌کنند. اولین مرحله، mount نام دارد و زمانی رخ می‌دهد که وهله‌ای از یک کامپوننت، ایجاد و به DOM افزوده شده‌است. در این حالت تعدادی متد خاص را می‌توان به کامپوننت خود اضافه کرد که به صورت خودکار توسط React فراخوانی می‌شوند. به این متدها Lifecycle Hooks می‌گویند. در طی مرحله‌ی mount، سه متد Lifecycle Hooks مخصوص constructor، render و componentDidMount قابل تعریف هستند. React این متدها را به ترتیب فراخوانی می‌کند. دومین مرحله، update نام دارد و زمانی رخ می‌دهد که state و یا props کامپوننت تغییر می‌کنند. در طی مرحله‌ی update، دو متد Lifecycle Hooks مخصوص render و componentDidUpdate قابل تعریف هستند. آخرین فاز یا مرحله، unmount نام دارد و زمانی رخ می‌دهد که کامپوننتی از DOM حذف می‌شود، مانند حذف کامپوننت Counter در قسمت‌های قبل. در طی مرحله‌ی unmount، یک متد Lifecycle Hooks مخصوص componentWillUnmount قابل تعریف است.
البته این Lifecycle Hooks ای که در اینجا نام برده شدند، بیشترین استفاده را دارند. در مستندات React مواردی دیگری نیز ذکر شده‌اند که در عمل آنچنان مورد استفاده قرار نمی‌گیرند.


مرحله‌ی Mount

در کامپوننت App، یک constructor را اضافه می‌کنیم تا بتوان مرحله‌ی Mount را بررسی کرد. این سازنده تنها یکبار در زمان وهله سازی این کامپوننت فراخوانی می‌شود. یکی از کاربردهای آن می‌تواند مقدار دهی اولیه‌ی خواص این وهله باشد. برای مثال یکی از کاربردهای آن می‌تواند مقدار دهی اولیه‌ی state بر اساس مقادیر props رسیده باشد.  در اینجا است که می‌توان خاصیت state را مستقیما مقدار دهی کرد (مانند this.state = this.props.something) و در این حالت نیازی به فراخوانی متد this.setState نیست و اگر فراخوانی شود، یک خطا را دریافت می‌کنیم. از این جهت که this.setState را تنها زمانیکه کامپوننتی رندر شده و در DOM قرار گرفته باشد، می‌توان فراخوانی کرد.

یک نکته: فراخوانی this.state = this.props.something در سازنده‌ی کلاس میسر نیست، مگر اینکه props را به صورت پارامتر به سازنده‌ی کلاس و سازنده‌ی base class توسط متد super ارسال کنیم:
  constructor(props) {
    super(props);
    console.log("App - constructor");
    this.state = this.props.something;
  }
در غیراینصورت this.props، مقدار undefined را بازگشت می‌دهد.

دومین متد lifecycle hooks ای که بررسی می‌کنیم، componentDidMount است:
class App extends Component {
  constructor() {
    super();
    console.log("App - constructor");
  }

  componentDidMount() {
    // Ajax calls
    console.log("App - mounted");
  }
این متد پس از رندر کامپوننت در DOM فراخوانی می‌شود و بهترین محلی است که از آن می‌توان برای ارسال درخواست‌های Ajaxای به سمت سرور و دریافت اطلاعات از backend، استفاده کرد و سپس setState را با اطلاعات جدید فراخوانی نمود.

سومین lifecycle hooks در مرحله‌ی mounting، متد رندر است که در اینجا به ابتدای آن، یک  console.logرا جهت بررسی بیشتر اضافه می‌کنیم:
  render() {
    console.log("App - rendered");
در این حالت اگر برنامه را اجرا کنیم، چنین خروجی را می‌توان در کنسول توسعه دهندگان مرورگر مشاهده کرد:


در اینجا ترتیب فراخوانی این متدها را مشاهده می‌کنید. ابتدا سازنده‌ی کلاس فراخوانی شده‌است. سپس در مرحله‌ی رندر، یک المان React که در DOM مجازی React قرار می‌گیرد، بازگشت داده می‌شود. سپس React این DOM مجازی را با DOM اصلی هماهنگ می‌کند. پس از آن مرحله‌ی Mount فرا می‌رسد. یعنی در این مرحله، کامپوننت در DOM اصلی قرار دارد. اینجا است که اعمال Ajax ای دریافت اطلاعات از سرور باید انجام شوند.

یک نکته: در مرحله‌ی رندر، تمام فرزندان یک کامپوننت نیز به صورت بازگشتی رندر می‌شوند. برای نمایش این ویژگی، به متد Render کامپوننت‌های NavBar، Counters و Counter، متد  console.log ای را جهت درج این مرحله در کنسول، اضافه می‌کنیم:
class Counter extends Component {
  render() {
    console.log("Counter - rendered");
//...

class Counters extends Component {
  render() {
    console.log("Counters - rendered");
//...

const NavBar = ({ totalCounters }) => {
  console.log("NavBar - rendered");
//...

یک نکته: نمی‌توان از lifecycle hooks در کامپوننت‌های بدون حالت تابعی استفاده کرد.

پس از این تغییرات و ذخیره سازی برنامه، با بارگذاری مجدد آن در مرورگر، چنین خروجی در کنسول توسعه دهندگان مرورگر ظاهر می‌شود:


همانطور که مشاهده می‌کنید، پس از فراخوانی App - rendered، تمام فرزندان کامپوننت App رندر شده‌اند و در آخر به App - mounted رسیده‌ایم.


مرحله‌ی Update

مرحله‌ی Update زمانی رخ می‌دهد که state و یا props یک کامپوننت تغییر می‌کنند. برای مثال با کلیک بر روی دکمه‌ی Increment، وضعیت کامپوننت به روز رسانی می‌شود. پس از آن فراخوانی خودکار متد رندر در صف قرار می‌گیرد. به این معنا که تمام فرزندان آن نیز قرار است مجددا رندر شوند. برای آزمایش آن، یکبار لاگ‌های کنسول توسعه دهندگان مرورگر را پاک کنید. سپس بر روی دکمه‌ی Increment کلیک کنید:


همانطور که ملاحظه می‌کنید با کلیک بر روی دکمه‌ی Increment، کل Component tree برنامه مجددا رندر شده‌است. البته این مورد به معنای به روز رسانی کل DOM اصلی در مرورگر نیست. زمانیکه کامپوننتی رندر می‌شود، فقط یک React element حاصل آن خواهد بود که در نتیجه‌ی آن DOM مجازی React به روز رسانی خواهد شد. سپس React، کپی DOM مجازی قبلی را با نمونه‌ی جدید آن مقایسه می‌کند. در آخر، محاسبه‌ی تغییرات صورت گرفته و تنها بر اساس موارد تغییر یافته‌است که DOM اصلی را به روز رسانی می‌کند. به همین جهت زمانیکه بر روی دکمه‌ی Increment کلیک می‌شود، فقط span کنار آن در DOM اصلی به روز رسانی می‌شود. برای اثبات آن در مرورگر بر روی المان span که شماره‌ها را نمایش می‌دهد، کلیک راست کرده و گزینه‌ی inspect را انتخاب کنید. سپس بر روی دکمه‌ی Increment کلیک نمائید. مرورگر قسمتی را که به روز می‌شود، با رنگی مشخص و متمایز، به صورت لحظه‌ای نمایش می‌دهد.

متد componentDidUpdate، پس از به روز رسانی کامپوننت فراخوانی می‌شود. به این معنا که در این حالت وضعیت و یا props جدیدی را داریم. در این حالت می‌توان این اشیاء به روز شده را با نمونه‌های قبلی آن‌ها مقایسه کرد و در صورت وجود تغییری، برای مثال یک درخواست Ajax ای را به سمت سرور برای دریافت اطلاعات تکمیلی ارسال کرد و در غیراینصورت خیر. بنابراین می‌توان به آن به عنوان یک روش بهینه سازی نگاه کرد. برای نمایش این قابلیت می‌توان متد componentDidUpdate را که مقادیر قبلی props و state را دریافت می‌کند، لاگ کرد:
class Counter extends Component {
  componentDidUpdate(prevProps, prevState) {
    console.log("Counter - updated", { prevProps, prevState });
    if (prevProps.counter.value !== this.props.counter.value) {
      // Ajax call and get new data
    }
  }
برای آزمایش آن، یکبار لاگ‌های کنسول توسعه دهندگان مرورگر را پاک کنید. سپس بر روی دکمه‌ی Increment اولین شمارشگر کلیک کنید:


همانطور که مشاهده می‌کنید، مقدار شیء counter، پیش از کلیک بر روی دکمه‌ی Increment، مساوی 4 بوده‌است. در یک چنین حالتی می‌توان مقدار قبلی prevProps.counter.value را با مقدار جدید this.props.counter.value مقایسه کرد و در صورت نیاز یک درخواست Ajax ای را برای دریافت اطلاعات به روز، صادر کرد.


مرحله‌ی Unmount

در این مرحله تنها یک lifecycle hook به نام componentWillUnmount قابل تعریف است که درست پیش از حذف یک کامپوننت از DOM فراخونی می‌شود.
class Counter extends Component {
  componentWillUnmount(){
    console.log("Counter - Unmount");
  }
پس از افزودن متد فوق و بارگذاری مجدد برنامه در مرورگر، یکبار دیگر لاگ‌های کنسول توسعه دهندگان مرورگر را پاک کنید. سپس اولین Counter رندر شده را حذف کنید.


در اینجا پس از حذف یک کامپوننت، state کامپوننت App تغییر کرده‌است. به همین جهت کل Component tree رندر مجدد شده‌است. اینبار یک DOM مجازی جدید را داریم که تعداد Counterهای آن 3 مورد است. سپس React این DOM مجازی جدید را با نمونه‌ی قبلی خود مقایسه کرده و متوجه می‌شود که یکی از Counterها حذف شده‌است. در ادامه متد componentWillUnmount را پیش از حذف این ‍Counter از DOM، فراخوانی می‌کند. به این ترتیب فرصت خواهیم یافت تا رهاسازی منابع را در صورت نیاز انجام دهیم تا برنامه دچار نشتی حافظه نشود.


یک مثال: افزودن دکمه‌ی Decrement به کامپوننت Counter

در ادامه می‌خواهیم دکمه‌ای را برای کاهش مقدار یک شمارشگر، به کامپوننت Counter اضافه کنیم. همچنین اگر مقدار value شمارشگر مساوی صفر بود، دکمه‌ی کاهش مقدار آن باید غیرفعال شود و برعکس. به علاوه از سیستم طرحبندی بوت استرپ نیز برای تعریف دو ستون، یکی برای نمایش مقدار شمارشگرها و دیگری برای نمایش دکمه‌ها استفاده خواهیم کرد.


برای پیاده سازی آن ابتدا متد رندر کامپوننت Counter را به صورت زیر تغییر می‌دهیم:
class Counter extends Component {

  render() {
    console.log("Counter - rendered");
    return (
      <div className="row">
        <div className="col-1">
          <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
        </div>
        <div className="col">
          <button
            onClick={() => this.props.onIncrement(this.props.counter)}
            className="btn btn-secondary btn-sm"
          >
            +
          </button>
          <button
            onClick={() => this.props.onDecrement(this.props.counter)}
            className="btn btn-secondary btn-sm m-2"
            disabled={this.props.counter.value === 0 ? "disabled" : ""}
          >
            -
          </button>
          <button
            onClick={() => this.props.onDelete(this.props.counter.id)}
            className="btn btn-danger btn-sm"
          >
            Delete
          </button>
        </div>
      </div>
    );
  }
در اینجا یک row تعریف شده و سپس دو div، با کلاس‌های تعیین عرض ستون‌ها. در ادامه span نمایش شمارشگر، به div اول و دکمه‌ها به div دوم منتقل شده‌اند. همچنین marginها را هم اصلاح کرده‌ایم تا بین دکمه‌ها فضای مناسبی ایجاد شود.
در این بین، دکمه‌ی جدید کاهش مقدار را که با یک - مشخص شده‌است نیز مشاهده می‌کنید. رویدادگردان onClick آن به this.props.onDecrement اشاره می‌کند. همچنین ویژگی disabled نیز به آن اضافه شده‌است تا بر اساس مقدار value شیء counter، در مورد فعال یا غیرفعالسازی دکمه تصمیم گیری کند.
پس از آن نیاز است این this.props.onDecrement را تعریف کنیم. به همین جهت به والد آن که کامپوننت Counters است مراجعه کرده و آن‌را به صورت زیر تغییر می‌دهیم:
<Counter
  key={counter.id}
  counter={counter}
  onDelete={this.props.onDelete}
  onIncrement={this.props.onIncrement}
  onDecrement={this.props.onDecrement}
/>
در اینجا onDecrement اضافه شده‌است تا شیء this.props ارسالی به کامپوننت Counter را مقدار دهی کند. اکنون باید ارجاع به this.props.onDecrement این کامپوننت را نیز تکمیل کرد. این ارجاع نیز به والد Counters که در اینجا کامپوننت App است اشاره می‌کند:
<Counters
  counters={this.state.counters}
  onReset={this.handleReset}
  onIncrement={this.handleIncrement}
  onDecrement={this.handleDecrement}
  onDelete={this.handleDelete}
/>
در کامپوننت App، ویژگی onDecrement ارسالی به کامپوننت Counters، به صورت props مقدار دهی شده‌است. این ویژگی به متد this.handleDecrement اشاره می‌کند که به صورت زیر در کامپوننت App تعریف می‌شود:
  handleDecrement = counter => {
    console.log("handleDecrement", counter);
    const counters = [...this.state.counters]; // cloning an array
    const index = counters.indexOf(counter);
    counters[index] = { ...counter }; // cloning an object
    counters[index].value--;
    console.log("this.state.counters", this.state.counters[index]);
    this.setState({ counters });
  };
که کدهای آن با کدهای handleIncrement بحث شده‌ی در قسمت قبل یکی است. اکنون اگر برنامه را اجرا کنید، به تصویر ابتدای توضیحات این مثال خواهید رسید.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-09.zip
نظرات مطالب
Vue.js - بحث Event Handling - آشنایی و شیوۀ استفاده از رویدادها - قسمت پنجم
یک نکته‌ی تکمیلی: نحوه‌ی انتخاب یک المنت در Vue.js

در Vue.js  چندین روش برای انتخاب یک المنت وجود دارند که در ادامه آن‌ها را مورد بررسی قرار میدهیم.
 کد زیر را در نظر بگیرید، ما قصد داریم value موجود در input  را نمایش دهیم.

روش اول: با استفاده از جاوا اسکریپت
<!DOCTYPE html>

<head>
    <meta charset="UTF-8">
    <title>Vue.js گرفتن یک المنت در </title>
</head>

<body>
    <div id="main">
        <input type="text" name="fullName" id="fullName">
        <button @click='getFullNameValue()'>Show Me</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el: '#main',
            data() {
                return {

                }
            },
            methods: {
                getFullNameValue() {
                    let fullNameValue = document.querySelector('#fullName').value;
                    alert(fullNameValue);
                }
            }
        });
    </script>
</body>

</html>
با استفاده از دستور زیر در جاوا اسکریپت براحتی میتوانیم یک المنت را انتخاب کنیم و آن را به یک متغیر انتساب دهیم.
 let fullNameValue = document.querySelector('#fullName')

روش دوم: انتخاب یک المنت با جی کوئری (با سلکتور دلخواه)
getFullNameValue() {
                    //let fullNameValue = document.querySelector('#fullName').value;
                    let fullNameValue = $('#fullName');
                    alert(fullNameValue.val());
}

روش سوم: انتخاب یک المنت در حیطه نمونه سازی شده  Vue.js
getFullNameValue() {
                    //let fullNameValue = document.querySelector('#fullName').value;
                    //let fullNameValue = $('#fullName').val();
                    let fullNameValue = this.$el.querySelector('#fullName');
                    alert(fullNameValue.value );
}

روش چهارم: انتخاب یک المنت از طریق امکان ref  در  Vue.js
<!DOCTYPE html>

<head>
    <meta charset="UTF-8">
    <title>Vue.js گرفتن یک المنت در </title>
</head>

<body>
    <div id="main">
        <input type="text" name="fullName" id="fullName" ref="refFullName">
        <button @click='getFullNameValue()'>Show Me</button>
    </div>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script>
        new Vue({
            el: '#main',
            data() {
                return {

                }
            },
            methods: {
                getFullNameValue() {
                    //let fullNameValue = document.querySelector('#fullName').value;
                    //let fullNameValue = $('#fullName').val();
                    //let fullNameValue = this.$el.querySelector('#fullName').value;
                    let fullNameValue = this.$refs.refFullName;
                    alert(fullNameValue.value);
                }
            }
        });
    </script>
</body>

</html>

نتیجه گیری:
از لحاظ performance  روش سوم و چهارم بهینه می‌باشند؛ زیرا فقط در حیطه نمونه سازی شده  Vue.js  مربوطه جستجوی المنت را انجام میدهند. درحالیکه در روش اول و دوم کل DOM  مورد بررسی قرار میگیرد. روش چهارم بخاطر سهولت نوشتاری بهتر از سایر موارد می‌باشد.
چند نکته در مورد کد فوق:
A) در ES6 نیازی به نوشتن کلمه کلیدی function برای تعریف یک متد نیست.
 getFullNameValue: function() {
                  ...
                }
و میتوان بصورتی که در مثال کد استفاده شده، آن را خلاصه نمود.
B)  در ورژن جدید  Vue.js  بجای استفاده از دایرکتیو  v-on  ( کد زیر ) برای تعریف یک رویداد میتوان از  @ استفاه نمود. در مثال مورد استفاده‌ی مقاله از @ استفاده شده است.
  <button v-on:click='getFullNameValue()'>Show Me</button>

مطالب
کامپوننت‌های راهبری سایت در بوت استرپ 4
پس از سیستم طرحبندی بوت استرپ، مهم‌ترین کامپوننت‌های آن، کامپوننت‌های راهبری سایت مانند Navs ،Tabs ،Pills و Navbars هستند. Navbars در بوت استرپ 4 نسبت به نگارش سوم آن بازنویسی کامل شده‌اند و شامل بهبودهای قابل ملاحظه‌ای هستند.


کامپوننت‌های Nav در بوت استرپ 4

کامپوننت‌های گروه Nav‌، در نگارش 4 آن به علت استفاده‌ی از Flexbox، تغییرات بسیاری داشته‌اند و در نتیجه‌ی آن، انعطاف پذیرتر و ساده‌تر شده‌اند.
در ابتدا لیست ساده‌ی زیر را در نظر بگیرید. تنظیمات ابتدایی آن برای تبدیل به منوی راهبری بالای سایت به صورت زیر است:
<body>
    <div class="container">
        <div class="row">
            <section class="col-12">
                <ul class="nav">
                    <li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
                    <li class="nav-item"><a class="nav-link" href="#">Mission</a></li>
                    <li class="nav-item"><a class="nav-link" href="#">Services</a></li>
                    <li class="nav-item"><a class="nav-link" href="#">Staff</a></li>
                    <li class="nav-item"><a class="nav-link disabled" href="#">Testimonials</a></li>
                </ul>
</div>
    </div>
</body>
ابتدا کلاس nav به یک ul اضافه می‌شود. سپس به هر آیتم آن، کلاس nav-item را اضافه می‌کنیم. در آخر به هر لینک آن نیز کلاس nav-link نسبت داده می‌شود:


در اینجا دو کلاس active و disabled نیز به لینک‌های منوی راهبری اضافه شده‌اند. البته این کلاس‌ها تا تکمیل نهایی nav‌، ظاهر آنچنان متفاوتی را ارائه نمی‌دهند.
اولین شیوه‌نامه‌ای را که می‌توان به nav اضافه کرد، nav-pills است:
<ul class="nav nav-pills">


Pills شبیه به دکمه‌ها هستند و در این حالت لینک active، واضح‌تر به نظر می‌رسد.
و یا می‌توان nav-tabs را به nav افزود:
<ul class="nav nav-tabs">


روش دیگر تعریف nav، استفاده از المان nav و سپس حذف ul و li و همچنین nav-item است:
<nav class="nav nav-pills justify-content-center">
    <a class="nav-link active" href="#">Home</a>
    <a class="nav-link" href="#">Mission</a>
    <a class="nav-link" href="#">Services</a>
    <a class="nav-link" href="#">Staff</a>
    <a class="nav-link disabled" href="#">Testimonials</a>
</nav>
در اینجا امکان کار با کلاس‌های Flexbox، مانند justify-content-center را نیز مشاهده می‌کنید. برای مثال برای هدایت منوی راهبری به سمت چپ و یا راست صفحه می‌توان بجای center، از end و یا start استفاده کرد. انجام یک چنین کارهایی در نگارش‌های قبلی بوت استرپ بدون Flexbox، مشکل بودند.
کلاس دیگری را که در اینجا می‌توان استفاده کرد، flex-column است تا آیتم‌های nav، بجای نمایش در یک ردیف، در یک ستون ظاهر شوند:


و یا می‌توان با استفاده از break-points، سبب شد تا اگر اندازه‌ی صفحه بیش از sm بود، آیتم‌های منوی راهبری، ردیفی و اگر کمتر از آن بود (حالت موبایل)، ستونی نمایش داده شوند:
<nav class="nav nav-pills justify-content-center flex-column flex-sm-row">


ایجاد navbars در بوت استرپ 4

Navbar بوت استرپ 4، بازنویسی کامل شده و کار کردن با آن نسبت به نگارش سوم آن بسیار ساده‌تر شده‌است.
<body>
    <nav class="navbar bg-dark navbar-dark navbar-expand-sm">
        <div class="container">
            <div class="navbar-nav">
                <a class="nav-item nav-link active" href="#">Home</a>
                <a class="nav-item nav-link" href="#">Mission</a>
                <a class="nav-item nav-link" href="#">Services</a>
                <a class="nav-item nav-link" href="#">Staff</a>
                <a class="nav-item nav-link disabled" href="#">Testimonials</a>
            </div>
        </div>
    </nav>

    <div class="container">
با این خروجی:


در اینجا، کار با افزودن کلاس navbar به المان nav شروع می‌شود. سپس هر لینک داخل آن، کلاس‌های nav-item nav-link را پیدا می‌کند. در اینجا اگر آیتمی قرار است به صفحه‌ی جاری اشاره کند، با کلاس active مشخص خواهد شد.
سپس توسط  کلاس‌های bg-dark navbar-dark، رنگ‌های پس زمینه و رنگ متن مشخص شده‌اند. برای مثال می‌توان bg-light navbar-light را نیز آزمایش کرد:
<nav class="navbar bg-light navbar-light navbar-expand-sm">


و یا بجای این رنگ‌های پیش‌فرض، در بوت استرپ 4 می‌توان به سادگی رنگ navbar را توسط یک background-color دلخواه، سفارشی سازی کرد:
<nav class="navbar navbar-dark navbar-expand-sm" style="background-color:red">


کاری که در نگارش‌های پیشین بوت استرپ به سادگی میسر نبود.

همچنین اگر دقت کرده باشید از کلاس navbar-expand-sm نیز استفاده شده‌است. حالت پیش‌فرض نمایش آیتم‌های navbar، ستونی است و برای حالت موبایل درنظر گرفته شده‌است. استفاده‌ی از navbar-expand-sm سبب می‌شود تا پس از عرض sm، آیتم‌های navbar همانند شکل‌های فوق، در طی یک ردیف نمایش داده شوند و در عرض کمتر از sm، به صورت یک ستون:


به علاوه آیتم‌های navbar را داخل یک container قرار داده‌ایم:
<div class="container">
      <div class="navbar-nav">
علت اینجا است که چون navbar تعریف شده خارج از container اصلی است، اگر چنین کاری را انجام ندهیم، آیتم‌های آن از سمت چپ صفحه بدون تراز بودن با container ذیل آن نمایش داده خواهند شد. تعریف یک container داخل navbar، این مشکل عدم تراز بودن عمودی را برطرف می‌کند.


تعریف متون و لوگو در navbar بوت استرپ 4

برای تعریف متن لوگوی سایت در navbar به صورت زیر عمل می‌شود:
<body>
    <nav class="navbar bg-dark navbar-dark navbar-expand-sm">
        <div class="container">
            <div class="navbar-brand">
                Wisdom Pet Medicine
            </div>
            <div class="navbar-nav">
                <a class="nav-item nav-link active" href="#">Home</a>
                <a class="nav-item nav-link" href="#">Mission</a>
                <a class="nav-item nav-link" href="#">Services</a>
                <a class="nav-item nav-link" href="#">Staff</a>
                <a class="nav-item nav-link disabled" href="#">Testimonials</a>
            </div>
        </div>
    </nav>

    <div class="container">
در اینجا با استفاده از کلاس navbar-brand در یک div مجزا، سبب نمایش متن لوگوی سایت شده‌ایم:


و یا می‌توان بجای div، از المان anchor نیز استفاده کرد تا به صورت لینک نمایش داده شود:
<a class="navbar-brand" href="#"> Wisdom Pet Medicine </a>
و بجای متن، تصاویر را نیز می‌توان قرار داد.

برای تعریف متنی در navbar از کلاس navbar-text استفاده می‌شود:
<body>
    <nav class="navbar bg-dark navbar-dark navbar-expand-sm">
        <div class="container">
            <a class="navbar-brand d-none d-sm-inline-block" href="#"> Wisdom
                Pet Medicine </a>
            <div class="navbar-nav">
                <a class="nav-item nav-link active" href="#">Home</a>
                <a class="nav-item nav-link" href="#">Mission</a>
                <a class="nav-item nav-link" href="#">Services</a>
                <a class="nav-item nav-link" href="#">Staff</a>
                <a class="nav-item nav-link disabled" href="#">Testimonials</a>
            </div>
            <span class="navbar-text d-none d-xl-inline-block">The best in
                traditional and alternate
                medicine</span>
        </div>
    </nav>

    <div class="container">
اما چون این متن طولانی است، بهتر است آن‌را در اندازه‌ی صفحه‌ی xl نمایش دهیم. به همین جهت با افزودن کلاس d-none، آن‌را در تمام اندازه‌ها مخفی می‌کنیم. سپس با افزودن d-xl-inline-block، آن‌را پس از عرض xl نمایان خواهیم کرد.
همین تنظیم را به navbar-brand، در اندازه‌ی sm نیز اضافه کرده‌ایم تا لوگوی سایت در اندازه‌های موبایل ظاهر نشود.



افزودن drop downs به navbar در بوت استرپ 4

برای تبدیل یکی از آیتم‌های منوی راهبری، به منو، از dropdown استفاده می‌شود که نمونه‌ای از آن‌را در مثال زیر مشاهده می‌کنید:
<body>
    <nav class="navbar bg-dark navbar-dark navbar-expand-sm">
        <div class="container">
            <a class="navbar-brand d-none d-sm-inline-block" href="#">
                <img src="images/wisdompetlogo.svg" style="width:40px;" alt="">
                Wisdom Pet Medicine
            </a>
            <div class="navbar-nav ml-sm-auto">
                <a class="nav-item nav-link active" href="#">Home</a>
                <a class="nav-item nav-link" href="#">Mission</a>

                <div class="dropdown">
                    <a class="nav-item nav-link dropdown-toggle" data-toggle="dropdown"
                        id="servicesDropdown" aria-haspopup="true"
                        aria-expanded="false" href="#">Services</a>
                    <div class="dropdown-menu" aria-labelledby="servicesDropdown">
                        <a href="#" class="dropdown-item">Grooming</a>
                        <a href="#" class="dropdown-item">General Health</a>
                        <a href="#" class="dropdown-item">Nutrition</a>
                        <a href="#" class="dropdown-item">Pest Control</a>
                        <a href="#" class="dropdown-item">Vaccinations</a>
                    </div>
                </div>

                <a class="nav-item nav-link" href="#">Staff</a>
                <a class="nav-item nav-link disabled" href="#">Testimonials</a>
            </div>
            <span class="navbar-text d-none d-xl-inline-block">The best in
                traditional and alternate
                medicine</span>
        </div>
    </nav>

    <div class="container">
با این خروجی:


- دراپ‌داون نیاز به یک container دارد که آن‌را با تعریف یک div با کلاس dropdown تعریف کرده‌ایم.
- سپس به لینکی که قرار است آن‌را نمایش دهد، کلاس dropdown-toggle را اضافه می‌کنیم تا آیکن مثلثی رو به پایینی را نمایان کند. وجود این مثلث، بیانگر وجود منویی به همراه آن است.
- اکنون با تنظیم data-toggle به dropdown، کدهای جاوا اسکریپتی بوت استرپ، این المان را به صورت یک dropdown پردازش می‌کنند و نیازی به افزودن اسکریپتی به صفحه برای فعالسازی آن نیست. ویژگی‌های aria-expanded و aria-haspopup نیز به مقدار دهی پیش‌فرض‌های کدهای جاوا اسکریپتی آن کمک می‌کنند.
- خود منو توسط دربرگیرنده‌ای با کلاس dropdown-menu و آیتم‌هایی با کلاس dropdown-item تشکیل می‌شود.
- در ادامه برای متصل کردن این دربرگیرنده به لینک نمایش دهنده‌ی منو، یک id را به لینک انتساب می‌دهیم (به نام servicesDropdown) و سپس aria-labelledby دربرگیرنده را به این id، مقدار دهی می‌کنیم.
- در این مثال با استفاده از کلاس navbar-nav ml-sm-auto، سبب شده‌ایم تا منوی سایت، از لبه‌ی سمت راست صفحه پس از عرض sm، شروع شود.


افزودن المان‌های فرم‌ها به منوی راهبری سایت

برای اضافه کردن المان‌های فرم به منوی راهبری سایت، ابتدا نیاز است کلاس form-inline را بر روی container این فرم قرار داد و سپس به ورودی‌های این فرم، کلاس form-control را اضافه می‌کنیم. اگر نیاز بود، توسط کلاس‌های margin و padding مخصوص بوت استرپ 4 مانند mr-2 نیز می‌توان بین آن‌ها فاصله ایجاد کرد:
<body>
    <nav class="navbar navbar-dark bg-dark navbar-expand-sm">
        <div class="container">
            <div class="navbar-nav">
                <a class="nav-item nav-link active" href="#">Home</a>
                <a class="nav-item nav-link" href="#">Mission</a>
                <a class="nav-item nav-link" href="#">Services</a>
                <a class="nav-item nav-link" href="#">Staff</a>
                <a class="nav-item nav-link" href="#">Testimonials</a>
            </div>
            <form class="form-inline">
                <input type="text" placeholder="Search..." class="form-control mr-2">
                <button class="btn btn-outline-light" type="submit">Go</button>
            </form>
        </div>
    </nav>

    <div class="container">
با این خروجی:


بوت استرپ در اندازه‌ی بزرگتر صفحه، فرم را به سمت راست و آیتم‌های منو را در سمت چپ نمایش می‌دهد.


کنترل محل قرارگیری المان‌ها در منوی راهبری سایت

توسط کلاس‌هایی مانند fixed-top (قرار گرفتن در بالای صفحه)، fixed-bottom (قرار گرفتن در پایین صفحه) و sticky-top، می‌توان محل قرارگیری منوی راهبری را تغییر داد. این کلاس‌ها را در مطلب «طرحبندی صفحات وب با بوت استرپ 4 - قسمت دوم» پیشتر بررسی کردیم.
برای توضیح حالت sticky-top، فرض کنید بالای منو، تصویر بزرگی از لوگوی سایت را دارید و این منو زیر آن قرار گرفته‌است. زمانیکه صفحه به سمت پایین اسکرول می‌شود، این منو نیز پایین خواهد آمد تا جائیکه در لبه‌ی بالای صفحه قرار گیرد. پس از آن، این منو در همین ناحیه باقی مانده و شبیه به fixed-top عمل می‌کند.

یک نکته: اگر fixed-bottom را مورد استفاده قرار دادید:
<nav class="navbar navbar-dark bg-dark navbar-expand-sm fixed-bottom">
 ممکن است متن پایین صفحه زیر این منو قرار گیرد و قابل خوانده شدن نباشد. برای این منظور می‌توان از کلاس margin-bottom بر روی container استفاده کرد:
<div class="container mb-5">



اضافه کردن منوی همبرگری به منوی راهبری سایت

در مورد کلاس navbar-expand-sm در این مطلب توضیح دادیم. هرچند قابلیت عمودی و افقی شدن خودکار آیتم‌های منوی راهبری بسیار جالب و کاربری است، اما در صفحات نمایشی کوچک، این نمایش عمودی می‌تواند ارتفاع قابل ملاحظه‌ای را به خود اختصاص دهد. به همین جهت می‌خواهیم نمایش آیتم‌های آن‌را وابسته به تصمیم کاربر کنیم.
<body>
    <nav class="navbar navbar-dark bg-dark navbar-expand-sm">
        <div class="container">
            <a href="#" class="navbar-brand">Wisdom Pet Medicine</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse"
                data-target="#myToggle" aria-controls="myToggle" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="myToggle">
                <div class="navbar-nav">
                    <a class="nav-item nav-link active" href="#">Home</a>
                    <a class="nav-item nav-link" href="#">Mission</a>
                    <a class="nav-item nav-link" href="#">Services</a>
                    <a class="nav-item nav-link" href="#">Staff</a>
                    <a class="nav-item nav-link" href="#">Testimonials</a>
                </div>
            </div>
        </div>
    </nav>

    <div class="container">
- در اینجا نحوه‌ی پیاده سازی منوی همبرگری را در بوت استرپ 4 ملاحظه می‌کنید.
- ابتدا نیاز است دکمه‌ی این منو اضافه شود که توسط کلاس navbar-toggler مشخص شده‌است. سپس با توجه به اینکه این کامپوننت توسط کدهای جاوا اسکریپتی بوت استرپ کار می‌کند، اطلاعات مورد نیاز آن‌را توسط ویژگی‌های data-toggle، data-target و aria مشخص می‌کنیم.
- این دکمه نیاز دارد تا به یک div با کلاس collapse navbar-collapse متصل شود. این اتصال نیز از طریق id آن صورت می‌گیرد که در ویژگی data-target مقدار دهی شده‌است.
- اگر این دکمه را پس از navbar-brand قرار دهیم، در سمت چپ صفحه و اگر پیش از آن قرار دهیم، در سمت راست صفحه ظاهر می‌شود.

در حالت نمایش sm، آیتم‌های منو مخفی شده:


با کلیک بر روی دکمه‌ی منوی همبرگری آن، گزینه‌های منو نمایش داده می‌شوند:


و در حالت اندازه‌ی بزرگتر صفحه، محو می‌شود:




کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: Bootstrap4_07.zip
مطالب
آشنایی با JS Link در شیرپوینت 2013
شیرپوینت 2013 تغییرات محسوسی در ظاهر خود و در واسط کاربریش اعمال کرده است . یکی از این تغییرات JS Link است که به کاربر امکان مدیریت روی Render کردن موجودیت‌های روی صفحه مانند فیلد‌ها ، آیتم‌ها و وب پارت‌ها را به کمک جاوااسکریپت می‌دهد. در این پست نحوه استفاده از این ویژگی جدید را بیان می‌کنم .

وارد سایت شده و یک لیست ایجاد کنید . (در اینجا از Custom List استفاده می‌کنیم .)


و ان را داده آمایی می‌کنیم . هدف این است که بر مبنای عدد موجود در لیست ، رنگ زمینه آن ایتم تغییر کند .


یک فایل جاوااسکریپت ایجاد کنید و کد زیر را در آن ذخیره کنید (از اینجا دانلود کنید) :
(function () {
    var itemCtx = {};
    itemCtx.Templates = {};
    itemCtx.Templates.Header = "<div><b title=\"اطلاعات فیلم ها\">Movie Data</b></div><ul>";
    itemCtx.Templates.Item = MyOverrideTemplate;
    itemCtx.Templates.Footer = "</ul>";
    itemCtx.BaseViewID = 1;
    itemCtx.ListTemplateType = 100; 
//For Generic List (More : http://msdn.microsoft.com/en-us/library/ms462947(v=office.12).aspx)

    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);

})();



function GT(val , index)
{
    // example of val : 60 %
    var temp = val.split(' ')[0];
    var v = Number(temp);
    return v > index;
}

function LT(val, index) {
    var temp = val.split(' ')[0];
    var v = Number(temp);
    return v < index;
}

function EQ(val, index) {
    var temp = val.split(' ')[0];
    var v = Number(temp);
    return v == index;
}



function MyOverrideTemplate(ctx) {

   

    if (LT(ctx.CurrentItem.PopularityPercent ,25))
    {
        return "<li title='خیلی کم بازدید' style='color:white;background-color: red;width: 300px;height: 24px;'>" +
            ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
    }
    else
    if (LT(ctx.CurrentItem.PopularityPercent ,50))
    {
        return "<li title='کم بازدید'  style='color:maroon;background-color: #ffcc00;width: 300px;height: 24px;'>" +
            ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
    }
    else
    if (LT(ctx.CurrentItem.PopularityPercent ,75))
    {
        return "<li title='بازدید معمولی'  style='color:#ffcc00;background-color: maroon;width: 300px;height: 24px;'>" +
            ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
    }
    else
    if (LT(ctx.CurrentItem.PopularityPercent ,95))
    {
        return "<li title='پر بازدید'  style='color:yellow;background-color: blue;width: 300px;height: 24px;'>" +
            ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
    }
    else
        if (EQ(ctx.CurrentItem.PopularityPercent, 100)) {
            return "<li  title='بالاترین بازدید'  style='color:black;background-color: green;width: 300px;height: 24px;'>" +
                ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
        }
        else {
            return "<li title='نامعلوم'  style='color:navy;background-color: yellow;width: 300px;height: 24px;'>" +
                ctx.CurrentItem.Title + " – " + ctx.CurrentItem.PopularityPercent + "</li>";
        }
}

حال وارد Site Setting شده و وارد Master Pages شوید

   
 فایل جاوااسکریپت فوق را از قسمت ریبون و تب Document آپلود کنید و منتظر بمانید تا پس از بارگذاری پنجره ویژگی‌های فایل نمایش داده شود



هنگلام پر کردن فیلد‌ها به این نکات دقت کنید :
در قسمت Content Type گزینه جدیدی که در این نسخه از شیرپوینت اضافه شده یعنی JavaScript Display Template را انتخاب کنید


در قسمت Target Control Type یکی از سه گزینه view یا Form ویا Field باید انتخاب شوند که در اینجا View را انتخاب میکنیم
standalone را روی override تنظیم می‌کنیم . همچنین گزینه Target Scope را که مسیر اعمال فایل است به رووت تنظیم می‌کنیم
در نهایت شناسه List template را به توجه به لیست مورد نظر که در اینجا Custome list است مقدار دهی می‌کنیم . (بیشتر )
سپس اطلاعات را ذخیره می‌کنیم .

برای آزمایش این تغییرات بک صفحه می‌سازیم و وب پارت لیست مورد نظر را به آن اضافه می‌کنیم


سپس وارد تنظیمات وب پارت شده و وارد قسمت Miscellaneous می‌شویم


در قسمت JS Link مسیر فایل خود را به صور نسبی وارد کنید

~site/_catalogs/masterpage/MyJsLinkSample.js
و نتیجه نهایی :

در صورت بروز Exception در فایل جاوااسکریپت ، خطا به صورت زیر نمایش داده خواهد شد :