Base64 و کاربرد جالب آن
شاید یک کاربرد آن در CSS این هست که تصویر استفاده شده در فایل CSS به همراه سند CSS قابل جابجایی میباشد و نیاز نیست که تصویر بر روی هاست Upload شود.
مروری بر قابلیت جدید ASP.NET FriendlyUrls
<link href="css/StyleSheet.css" rel="stylesheet" type="text/css" />
PM> Install-Package jquery.mobile
<meta name="viewport" content="width=device-width">
<head> <meta name="viewport" content="width=device-width,initial-sclae=1" /> <link href="Content/jquery.mobile-1.1.0.css" rel="stylesheet" type="text/css" /> <script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script> <script src="Scripts/jquery.mobile-1.1.0.js" type="text/javascript"></script> <title></title> </head> <body> <div data-role="page"> <div data-role="header" data-theme="b"> <h1>this is a test </h1> </div> <div data-role="conent"> <ul data-role="listview" data-filter="true" data-inset="true" data-theme="e"> <li><a href="#">Water</a></li> <li><a href="#">Pepsi</a></li> <li><a href="#">Diet Pepsi</a></li> <li><a href="#">Beer</a></li> <a href="#" data-role="button" data-theme="b">Click ME</a> </ul> </div> <div data-role="footer" data-theme="b" data-position="fixed"> <h1>footer </h1> </div> </div> </body>
data-role="page"
" data-role="header
"data-theme="e
"data-role="listview
"data-filter="true
" data-inset="true"
- شناسایی منابع
- بکارگیری منابع از طریق نمایش آنها (منابع وب)
- پیامهای خودتوصیفی
- ابررسانه بعنوان قلب تپنده موقعیت برنامه
- درگیر نکردن برنامه “
- توزیع (HTTP , Feeds)
- ترکیب (Hypermedia , Mashups)
- امنیت (Open ID, SSL)
- قابلیت انتقال داده (XML,RDF)
- قابلیت نمایش داده (ATOM, JSON)
- متدهای انتقال (REST, HTTP, Bit Torrent)
- هر چیزی یک منبع است.
- هر منبعی یک تمثیل دارد.
- هر منبعی یک نام بخصوص دارد.
- انتقال موقعیت نیازمند کشف و شهود (Discovery) است.
- پروتکل شبکه پایه WOA میباشد
- اطلاعات در قالب منابع (Resources) نمایش مییابند.
- منابع توسط URIها شناخته میشوند.
- منابع از طریق HTTP اداره میشوند.
- معاهدات به صورت ضمنی در نمایش منابع میباشند.
- رابطها بطور کلی عام هستند.
- ساده سازی توسعه پذیری، مقیاس پذیری
- کاهش زمان توسعه ویژگیهای جدید
- کاهش زمان مهندسی مورد نیاز برای یکپارچه سازی
- سازنده فرصتهایی جدید برای mash-ups و دیگر داستانهای غیرقابل پیش بینی کاربری
- اما وضعیت ارتباطی کلاینتها و سرورها در WOA چگونه است ؟
- سرویسها وابسته به دیگر سرویسها هستند.
- ارتباطات از طریق HTTP صورت میگیرد.
- کلاینتها حکم منبع و سرویس دهی به دیگر کلاینتها را دارند.
- مقیاس پذیری ، توسعه پذیری == اتصالات داخی
بعنوان مثال میتوان با ترکیب تصاویر و آدرسهای مختلف دانشگاههای تهران، یک map Mashup درست کرد.
برای Photo Mashup ابزار Color Picker هم هست که امکان جستجوی تصاویر را بر اساس رنگ فراهم میکند و از سرویس اشتراک گذاری عکس Flickr استفاده میکند که در این آدرس قابل استفاده است.
معماری Mashup هم مثل معماری MVC (البته با تفاوتهای فاحش) سه لایهای است :
لایه نمایش / تعامل کاربر (همان رابط کاربری است)
تکنولوژیها : HTML/XHTML, CSS, Javascript, Asynchronous JS and Xml (Ajax).
وب سرویسها : عملکرد محصول از طریق سرویسهای API هم قابل دسترسی است
تکنولوژیها : XMLHTTPRequest, XML-RPC, JSON-RPC, SOAP, REST
داده : فراهم آوردن امکان ارسال ، مرتب سازی و دریافت داده
تکنولوژیها : XML , JSON , KML
از نظر معماری Mashup دارای 2 سبک است : الف) مبتنی بر وب – ب) مبتنی بر سرور
در ادامه با هم نمونه ای از استقرار معماری وب گرا WOA را در سازمان، بصورت شماتیک میبینیم. با هم مشاهده میکنیم با این پیاده سازی، موانع سر راه ما کاهش پیدا میکنند و سرعت یکپارچگی افزایش پیدا میکند. بدین صورت که میتوان از قدرت شبکه جهانی وب در جهت انتقال محتوای مورد نیازمان به هر جا و در هر زمانی بهره جست.
شاید برای شما سوال پیش بیاید که ما در معماری وب گرا بحث میکردیم، اصلا چرا وارد مفهوم Mashup شدیم؟
بهعبارت فنیتر چرا معماری وب گرا (WOA) برای Mashups اهمیت دارد ؟
پاسخ یک کلمه است : REST . همانطور که بالاتر نیز اشاره کردم، Mashup از REST بهره میبرد. به منظور افزایش اطلاعات در رابطه با REST باید گفت Roy Fielding آنرا بنیان نهادهاست. میخواهید او را بهتر معرفی کنم؟ وی یکی از خالقان HTTP است و مگر میتوان وب را بدون HTTP فرض کرد که مهمترین پروتکل انتقال ابر متن در جهان و پروتکل زیربنایی وب است؟!
REST به خوبی با معماری اینترنت عجین شده است! بپرسید چرا؟ چون پروتکل اصلی اینترنت HTTP است و هر دوی اینها از یک ذهن نشات گرفته و او کسی نیست جز Roy Fielding. اما باید بگویم REST یک استاندارد نیست؛ با وجود سادگی بسیار زیاد، تنها یک سبک استفاده از HTTP است.
REST همچنین از متدهای اختصاصی HTTP نظیر GET, PUT , POST , DELETE در بالای یک URL استفاده میکند تا نشان دهد چه رویدادی رخ میدهد.
در پایان گفتهها در رابطه با REST باید بگویم ATOM همان REST است. منظورم از ATOM ویرایشگر معروف متنی نیست که برای نوشتن کدهای برنامه نویسی استفاده قرار میگیرد؛ آنرا غالبا به شکل Atom مینویسند چرا که مخفف چند کلمه نیست و یک کلمه خاص است اما ATOM یک استاندارد وب به زبان XML است که برای خوراک وب بعنوان جایگزینی برای RSS استفاده میشود. ATOM را با AtomPub یا APP اشتباه نگیرید؛ چرا که APP پروتکل انتشاری است مبتنی بر پروتکل انتقال ابرمتن (HTTP) و برای به روزرسانی محتوی وب مورد استفاده قرار میگیرد.
در ادامه مباحث دررابطه با معماری وب گرا باید گفت WOA امروزه بعنوان مدل حاکم برنامههای تحت شبکه مطرح است. اما متاسفانه فروشندگان بزرگی در پشت آن حضور ندارند به همین دلیل آنچنان که باید عمومیت نیافته است. WOA همچنان میتواند بیشترین سود حاصل را از طریق شبکه فراهم کند. شاید بتوان گفت کوتاهترین مسیر برای رسیدن به چنین نتیجهای همین معماری وب گرا است.
فرمول جالبی هم برای تعریف وب ارائه شدهاست که با هم میبینیم :
HTTP + URIs = Web
ظرافت فرمول بالا به اهمیت پروتکل زیربنایی وب یعنی HTTP اشاره دارد. URI هم مجموعهای از رشتههاست که برای شناسایی یک منبع خاص تحت وب به کار میروند. در شکل زیر رابطه بین URI , URN , URL را بررسی میکنیم. URI تشکیل شدهاست از URL و URN .URL متد دسترسی به منبع را مشخص میکند، در حالیکه URN تنها مشخص کننده نام منبع میباشد و هیچگونه روشی را برای دسترسی به ما ارائه نمیدهد. بعنوان مثال یک شماره ISBN کتاب، یک نوع URN است.
مقاله کامل در مورد Threading در #C
معرفی کتابخانهی Redux Thunk
thunk، تابعی است که خروجی تابعی دیگر است؛ مانند مثال زیر:
function definitelyNotAThunk() { return function aThunk() { console.log('Hello, I am a thunk.'); } }
برای مثال فرض کنید که نیاز است یک فراخوانی Ajax ای صورت گیرد و پس از پایان آن، جهت به روز رسانی state، یک شیء اکشن، به سمت reducer متناظری dispatch شود. مشکل اینجا است که نمیتوان به Redux، یک callback حاصل از دریافت نتیجهی عملیات Ajax ای و یا یک Promise را ارسال کرد. تمام اینها یک اثر جانبی یا side effect هستند که با توابع خالص Redux ای سازگاری ندارند. برای مدیریت یک چنین مواردی، یک میانافزار را به نام redux-thunk ایجاد کردهاند که اجازهی dispatch تابعی را میدهد (همان thunk در اینجا) که قرار است action اصلی را در زمانی دیگر dispatch کند. به این ترتیب Redux اطلاعاتی را در مورد یک عمل async نخواهد داشت؛ میانافزاری در این بین آنرا دریافت میکند و زمانیکه آنرا dispatch میکنیم، آنگاه اکشن متناظر با آن، به redux منتقل میشود. به این ترتیب امکان منتظر ماندن تا زمان رسیدن پاسخ از شبکه، میسر میشود.
فرض کنید یک action creator متداول به صورت زیر ایجاد شدهاست:
export const getAllItems = () => ({ type: UPDATE_ALL_ITEMS, items, });
برای پاسخ به این سؤال، اینبار action creator فوق را بر اساس الگوی redux-thunk به صورت زیر بازنویسی میکنیم:
export const getAllItems = () => { return dispatch => { Api.getAll().then(items => { dispatch({ type: UPDATE_ALL_ITEMS, items, }); }); }; };
برپایی پیشنیازها
در اینجا برای افزودن کامپوننتی که اطلاعات خودش را از یک API خارجی تامین میکند، از همان برنامهی به همراه کامپوننت شمارشگر که در قسمت قبل آنرا تکمیل کردیم، استفاده میکنیم. فقط در آن کتابخانههای Axios و همچنین redux thunk را نیز نصب میکنید. به همین جهت در ریشهی پروژهی React این قسمت، دستور زیر را در خط فرمان صادر کنید:
> npm install --save axios redux-thunk
پس از نصب پیشنیازها و راه اندازی برنامهی backend، در ابتدا فایل src\config.json را جهت درج مشخصات آدرس REST Api، ایجاد میکنیم:
{ "apiUrl": "https://localhost:5001/api" }
افزودن میانافزار redux-thunk به برنامه
فرض کنید در قسمتی از صفحه، در کامپوننتی مجزا، دکمهای وجود دارد و با کلیک بر روی آن، قرار است اطلاعاتی از سرور دریافت شده و در کامپوننت مجزای دیگری نمایش داده شود:
چون نیاز به عملیات async وجود دارد، باید از میانافزار مخصوص thunk برای انجام آن استفاده کرد. برای این منظور به فایل src\index.js مراجعه کرده و میانافزار thunk را توسط تابع applyMiddleware، به متد createStore، معرفی میکنیم:
import { applyMiddleware, compose, createStore } from "redux"; import thunk from "redux-thunk"; //... const store = createStore( reducer, compose( applyMiddleware(thunk), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ) ); //...
دریافت اطلاعات از یک API خارجی به کمک redux-thunk
پس از آشنایی با روش کلی برقراری اتصالات سیستم react-redux در قسمت قبل، پیاده سازی دریافت اطلاعات را بر اساس همان الگو، پیاده سازی میکنیم:
1) ایجاد نام نوع اکشن متناظر با دکمهی افزودن مقدار
به فایل src\constants\ActionTypes.js، نوع جدید دریافت مطالب را اضافه میکنیم:
export const GetPostsSuccess = "GetPostsSuccess"; export const GetPostsStarted = "GetPostsStarted"; export const GetPostsFailure = "GetPostsFailure";
2) ایجاد متد Action Creator
در فایل src\actions\index.js، متد ایجاد کنندهی شیء اکشن ارسالی به reducer متناظری را تعریف میکنیم تا بتوان بر اساس نوع آن در reducer دریافت اطلاعات، منطق نهایی را پیاده سازی کرد:
import axios from "axios"; import { apiUrl } from "../config.json"; import * as types from "../constants/ActionTypes"; export const fetchPosts = () => { return (dispatch, getState) => { dispatch(getPostsStarted()); axios.get(apiUrl + "/posts").then(response => { dispatch(getPostsSuccess(response.data)).catch(err => { dispatch(getPostsFailure(err)); }); }); }; }; export const fetchPostsAsync = () => { return async (dispatch, getState) => { dispatch(getPostsStarted()); try { const { data } = await axios.get(apiUrl + "/posts"); console.log(data); dispatch(getPostsSuccess(data)); } catch (error) { dispatch(getPostsFailure(error)); } }; }; const getPostsSuccess = posts => ({ type: types.GetPostsSuccess, payload: { posts } }); const getPostsStarted = () => ({ type: types.GetPostsStarted }); const getPostsFailure = error => ({ type: types.GetPostsFailure, payload: { error } });
- تابع fetchPosts، از همان روش قدیمی callback، برای مدیریت اطلاعات دریافتی از سرور استفاده میکند. زمانیکه اطلاعاتی دریافت شد، آنرا با فراخوانی dispatch و با قالبی که تابع getPostsSuccess ارائه میدهد، به reducer متناظر، ارسال میکند.
- تابع fetchPostsAsync، نمونهی به همراه async/await کار با کتابخانهی axios است. هر دو روش callback و یا async/await در اینجا پشتیبانی میشوند.
به صورت پیشفرض action creators کتابخانهی redux از اعمال async پشتیبانی نمیکنند. برای رفع این مشکل پس از ثبت میانافزار thunk، اینبار متدهای action creator، بجای بازگشت یک شیء، یک تابع را بازگشت میدهند که این تابع درونی در زمانی دیگر توسط میانافزار thunk و پیش از رسیدن به reducer، فراخوانی خواهد شد. این تابع درونی، دو پارامتر dispatch و getState را دریافت میکند. هر دوی اینها نیز متد هستند. برای مثال اگر نیاز به دریافت وضعیت فعلی state در اینجا وجود داشت، میتوان متد ()getState رسیده را فراخوانی کرد و حاصل آنرا بررسی نمود. برای مثال شاید تصمیم گرفته شود که بر اساس وضعیت فعلی state، نیازی نیست تا اطلاعاتی از سرور دریافت شود و بهتر است همان اطلاعات کش شدهی موجود در state را بازگشت دهیم. البته در این مثال فقط از متد dispatch ارسالی، برای بازگشت نتیجهی نهایی به reducer متناظر، استفاده شدهاست.
- در نهایت آرایهی اشیاء مطلب دریافتی از سرور، به عنوان مقدار خاصیت posts شیء منتسب به خاصیت payload شیء ارسالی به reducer، در متد getPostsSuccess تعریف شدهاست. یعنی reducer متناظر، اطلاعات را از طریق خاصیت action.payload.posts شیء رسیده، دریافت میکند.
- همچنین دو اکشن شروع به دریافت اطلاعات (getPostsStarted) و بروز خطا (getPostsFailure) نیز در ابتدا و در قسمت catch عملیات async، به سمت reducer متناظر، dispatch خواهند شد.
3) ایجاد تابع reducer مخصوص دریافت اطلاعات از سرور
اکنون در فایل جدید src\reducers\posts.js، بر اساس نوع شیء رسیده و مقدار action.payload.posts آن، کار تامین آرایهی posts موجود در state انجام میشود:
import * as types from "../constants/ActionTypes"; const initialState = { loading: false, posts: [], error: null }; export default function postsReducer(state = initialState, action) { switch (action.type) { case types.GetPostsStarted: return { loading: true, posts: [], error: null }; case types.GetPostsSuccess: return { loading: false, posts: action.payload.posts, error: null }; case types.GetPostsFailure: return { loading: false, posts: [], error: action.payload.error }; default: return state; } }
- در حالت آغاز کار و یا GetPostsStarted، با تنظیم خاصیت loading به true، سبب نمایش یک div «لطفا منتظر بمانید» خواهیم شد.
- در حالت دریافت نهایی اطلاعات از سرور، خاصیت loading به false تنظیم میشود تا div «لطفا منتظر بمانید» را مخفی کند. همچنین آرایهی posts را نیز از payload رسیده استخراج کرده و به سمت کامپوننتها ارسال میکند.
- در حالت بروز خطا و یا GetPostsFailure، خاصیت error شیء action.payload استخراج شده و جهت نمایش div متناظری، بازگشت داده میشود.
پس از تعریف این reducer باید آنرا در فایل src\reducers\index.js به کمک combineReducers، با سایر reducerهای موجود، ترکیب و یکی کرد تا در نهایت این rootReducer در فایل index.js اصلی برنامه، جهت ایجاد store اصلی redux، مورد استفاده قرار گیرد:
import { combineReducers } from "redux"; import counterReducer from "./counter"; import postsReducer from "./posts"; const rootReducer = combineReducers({ counterReducer, postsReducer }); export default rootReducer;
تشکیل کامپوننتهای دکمهی دریافت اطلاعات و نمایش لیست مطالب
UI این قسمت از سه کامپوننت تشکیل شدهاست که کدهای کامل آنها را در ادامه مشاهده میکنید:
الف) کامپوننت src\components\FetchPosts.jsx
import React from "react"; const FetchPosts = ({ fetchPostsAsync }) => { return ( <section className="card mt-5"> <div className="card-header text-center"> <button className="btn btn-primary" onClick={fetchPostsAsync}> Fetch Posts </button> </div> </section> ); }; export default FetchPosts;
همانطور که مشاهده میکنید، این کامپوننت هیچ اطلاعاتی از وجود کامپوننت دومی که قرار است لیست مطالب را نمایش دهد، ندارد. کارش تنها dispatch یک اکشن است.
بنابراین این کامپوننت از طریق props فقط یک اشارهگر به متد رویدادگردانی را دریافت میکند و اطلاعات دیگری را نیاز ندارد.
ب) کامپوننت src\components\Posts.jsx
import React from "react"; import Post from "./Post"; const Posts = ({ posts, loading, error }) => { return ( <> <section className="card mt-5"> <div className="card-header"> <h2>Posts</h2> </div> <div className="card-body"> {loading ? ( <div className="alert alert-info">Loading ...</div> ) : ( <div className="list-group list-group-flush"> {posts.map(post => ( <Post key={post.id} post={post} /> ))} </div> )} {error && <div className="alert alert-warning">{error.message}</div>} </div> </section> </> ); }; export default Posts;
در این کامپوننت اگر loading رسیده به true تنظیم شده باشد، یک div با عبارت loading نمایش داده میشود. در غیراینصورت، لیست مطالب را درج میکند. همچنین اگر خطایی نیز رخ داده باشد، آنرا نیز درون یک div در صفحه نمایش میدهد.
ج) کامپوننت src\components\Post.jsx
import React from "react"; const Post = ({ post }) => { return ( <article className="list-group-item"> <header> <h2>{post.title}</h2> </header> <p>{post.body}</p> </article> ); }; export default Post;
اتصال کامپوننتهای FetchPosts و Posts به مخزن redux
مرحلهی آخر کار، تامین state کامپوننتهای FetchPosts و Posts از طریق props است. به همین جهت باید دو دربرگیرنده را برای این دو کامپوننت ایجاد کنیم.
الف) ایجاد دربرگیرندهی کامپوننت FetchPosts
برای این منظور فایل جدید src\containers\FetchPosts.js را با محتوای زیر ایجاد میکنیم:
import { connect } from "react-redux"; import { fetchPostsAsync } from "../actions"; import FetchPosts from "../components/FetchPosts"; const mapDispatchToProps = { fetchPostsAsync }; export default connect(null, mapDispatchToProps)(FetchPosts);
- چون اطلاعات state ای قرار نیست به این کامپوننت ارسال شود، تابع mapStateToProps را در اینجا مشاهده نمیکنید و با نال مقدار دهی شدهاست.
ب) ایجاد دربرگیرندهی کامپوننت Posts
برای این منظور فایل جدید src\containers\Posts.js را با محتوای زیر ایجاد میکنیم:
import { connect } from "react-redux"; import Posts from "../components/Posts"; const mapStateToProps = state => { console.log("PostsContainer->mapStateToProps", state); return { ...state.postsReducer }; }; export default connect(mapStateToProps)(Posts);
- کامپوننت Posts رویدادی را سبب نخواهد شد. به همین جهت تابع mapDispatchToProps را در اینجا تعریف و ذکر نکردهایم.
استفاده از کامپوننتهای دربرگیرنده جهت نمایش نهایی کامپوننتهای تحت کنترل Redux
اکنون به فایل src\App.js مراجعه کرده و دو تامین کنندهی فوق را درج میکنیم:
import "./App.css"; import React from "react"; import CounterContainer from "./containers/Counter"; import FetchPostsContainer from "./containers/FetchPosts"; import PostsContainer from "./containers/Posts"; function App() { const prop1 = 123; return ( <main className="container"> <div className="row"> <div className="col"> <CounterContainer prop1={prop1} /> </div> <div className="col"> <FetchPostsContainer /> </div> <div className="col"> <PostsContainer /> </div> </div> </main> ); } export default App;
یک نکته: برای مثال در انتهای کامپوننت FetchPosts، سطر export default FetchPosts را داریم. اگر این سطر را حذف کنیم و بجای آن export default connect فوق را قرار دهیم، دیگر نیازی نخواهد بود تا FetchPostsContainer را از دربرگیرندهها، import کرد و سپس بجای درج المان </FetchPosts> نوشت </FetchPostsContainer>. میتوان همانند قبل از همان نام متداول </FetchPosts> استفاده کرد و import انجام شده نیز همانند سابق از همان فایل ماژول کامپوننت صورت میگیرد. یعنی میتوان پوشهی containers را حذف کرد و کدهای آن را دقیقا ذیل کلاس کامپوننت درج نمود.
کدهای کامل این قسمت را میتوانید از اینجا دریافت کنید: state-management-redux-mobx-part04-backend.zip و state-management-redux-mobx-part04-frontend.zip
نحوه فارسی سازی فیلتر گرید کندو Kendo grid filter
سوالی که بنده درگیر اون شدم اینه که در پروژه فیلدی هست که تاریخ رو به صورت میلادی ذخیره میکنه . با مواردی که گفته شده نمایش تاریخ به صورت شمسی انجام شده اما وقتی که فیلتر روی این فیلد فعال میشه در گرید کندو در قسمت باکس فیلتر یک کامپوننت DatePicker میلادی ظاهر میشه .
متاسفانه تمامی راه هایی که میدونستم رو تست کردم اما به نتیجه خاصی نرسیدم .
1. تلاش شد که UI فیلتر به صورت رشته تعریف بشه توسط دستورهای Format. و UI. اما موارد ارائه شده برای این قسمت کارساز نبود .
2. تلاش شد که با استفاده از یک property جانبی از نوع رشته و تبدیل فیلد تاریخ در متدهای set و get این مسئله از راه دیگه حل بشه که نمایش اطلاعات موفقیت امیز بود اما در هنگام فیلتر متاسفانه به مشکلات تبدیل برخورد کردیم که قابل اصلاح نبود .
لطف بفرمایید راهنمایی کنید برای فیلتر تاریخ چه راهکاری وجود داره
همچنین اگر دقت کنید مثالی هم که در این صفحه هست DatePicker فیلتر ، تاریخ رو به صورت 7 اسفند 2016 نشون میده .
در تصویر بالا دو مسیر با آدرسهای : ShowPage1/ و ShowPage2/ تعریف شده است که هر کدام به یک view مشخص و یک Controller برای مدیریت آن اشاره میکند.
زمانی که ما از تزریق وابستگیها در AngularJs استفاده میکنیم و یک شیء را به کنترلر تزریق میکنیم، Angular توسط Injector$ سعی در پیدا کردن وابستگی مربوطه و سپس تزریق آن به کنترلر را انجام میدهد. برای استفاده از امکان مسیریابی Route ، ما نیز باید از پروایدر مخصوص آن برای تزریق استفاده کنیم. در Angular مسیرهای برنامه توسط پروایدری به نام routeProvider$ شناسایی میشود که خدمات مسیریابی را به ما ارائه میدهد. این سرویس به ما کمک میکند تا بتوانیم اتصال بین کنترلر ها، ویوها و آدرس URL جاری مرورگرها را به آسانی برقرار کنیم.
بهتر است کار را شروع کنیم . یک فایل JS ایجاد و سپس محتویات زیر را در آن قرار دهید :
var myFirstRoute = angular.module('myFirstRoute', []); myFirstRoute.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/pageOne', { templateUrl: 'templates/page_one.html', controller: 'ShowPage1Controller' }). when('/pageTwo', { templateUrl: 'templates/page_two.html', controller: 'ShowPage2Controller' }). otherwise({ redirectTo: '/pageOne' }); }]); myFirstRoute.controller('ShowPage1Controller', function($scope) { $scope.message = 'Content of page-one.html'; }); myFirstRoute.controller('ShowPage2Controller', function($scope) { $scope.message = 'Content of page-two.html'; });
در کدهای بالا ابتدا یک ماژول تعریف کرده ایم و سپس توسط ()config. تنظیمات مربوط به مسیریابی را انجام داده ایم. با استفاده از متدهای when. و otherwise. میتوانیم مسیرها را تعریف کنیم. برای هر مسیر دو پارامتر وجود دارد که اولین پارامتر نام مسیر و دومین پارامتر شامل 2 قسمت میشود که templateUrl آن آدرسی که باز خواهد شد و controller نیز نام کنترلری که ویو را مدیریت میکند.
توسط otherwise میتوانیم مسیر پیشفرض را نیز تعریف کنیم تا درصورتی که مسیری با آدرسهای بالای آن مطابقت نداشت به این آدرس منتقل شود.
در قطعه کد بالا همچنین دو مسیر با نامهای pageOne/ و pageTwo/ تعریف کرده ایم که هر کدام به ترتیب به Viewهای : templates/page_one.html و templates/page_two.html مرتبط شده اند. همچنین دو کنترلر برای مدیریت ویوها نیز تعریف شده است.
زمانی که ما آدرس http://appname/#pageOne را در نوار آدرس مرورگر وارد میکنیم، Angular به صورت اتوماتیک آدرس URL را با تنظیماتی که ما در اینجا تعریف کرده ایم مطابقت میدهد و در صورت وجود چنین آدرسی ، view مربوطه را بارگزاری میکند و در این مثال نیز مطابق با تنظیمات بالا، صفحهی templates/page_one.html برای ما بارگزاری و سپس کنترلر ShowPage1Controller را فراخوانی میکند ، جایی که ما منطق کار را در آن قرار میدهیم.
محتویات فایل main.html :
<body ng-app="app"> <div> <div> <div> <ul> <li><a href="#pageOne"> Show page one </a></li> <li><a href="#pageTwo"> Show page two </a></li> </ul> </div> <div> <div ng-view></div> </div> </div> </div> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script src="app.js"></script> </body>
در قطعه کد بالا دو لینک تعریف شده است که ویژگی href از علامت هش و نام صفحه تشکیل شده است. یکی از چیزهایی که شایان ذکر است ، دایرکتیو ng-view است. مکانی برای بارگزاری صفحات در آن.
ما میتوانیم این تگ را به سه شکل زیر نیز استفاده کنیم :
<div ng-view></div> .. <ng-view></ng-view> .. <div class="ng-view"></div>
محتویات صفحه templates/page_one.html :
<h2>Page One</h2> {{ message }}
محتویات صفحه templates/page_two.html :
<h2>Page Two</h2> {{ message }}
حال اگر پروژه را اجرا کنید و به کنسول مرور گر خود نگاه کنید متوجه میشوید که مسیریاب از مسیر پیشفرض استفاده کرده است و صفحهی page_one.html را به صورت ایجکسی فراخوانی کرده است :
و اگر روی لینک Show Page two کلیک کنید ، صفحهی page_two.html نیز به صورت ایجکسی فراخوانی میشود.
دوباره بر روی لینک Show page one کلیک کنید. بله. هیچ درخواستی به سمت سرور ارسال نشد و صفحهی page_one.html به خوبی نمایش داده شد. یکی از مزیتهای سیستم مسیریابی قابلیت کش کردن صفحات است تا در صورت فراخوانی مجدد، درخواستی به سمت سرور ارسال نشود و خیلی سریع به شما نمایش داده شود.
مثال این مطلب : RouteExample.zip
ادامه دارد ...