TypeScript और NativeScript के साथ एक मौसम वाली ऐप बनाएं
Hindi (हिंदी) translation by Ashish Rampal (you can also view the original English article)
इस ट्यूटोरियल में मैं आपको TypeScript लैंग्वेज का उपयोग करके NativeScript में एक मौसम वाली ऐप बनाने का तरीका दिखाऊंगा।
इस सीरीज के पिछले आर्टिकल में हमने प्लेन जावास्क्रिप्ट का उपयोग करके एक नोट लेने वाला ऐप बनाया था। इस बार हम TypeScript का उपयोग करने जा रहे हैं। पहले पता करें कि TypeScript NativeScript ऐप बनाने के लिए एक अच्छा विकल्प क्यों है।
1. TypeScript ही क्यों?
TypeScript NativeScript में फर्स्ट क्लास सिटीजन है। इसका उपयोग कोर NativeScript टीम द्वारा स्वयं NativeScript फ्रेम बनाने के लिए किया जाता है। यहां कुछ कारण बताए गए हैं कि आप NativeScript ऐप डेवलप करने के लिए TypeScript का उपयोग क्यों करना चाहेंगे:
- TypeScript जावास्क्रिप्ट में कंपाइल होता है। जब कंपाइलर चलता है, तो यह आपके कोड में हो सकने वाले किसी भी एरर को पकड़ लेता है ताकि आप NativeScript कंपाइलर के खत्म होने का इंतजार किए बिना तुरंत उन पर एक्शन कर सके। इसका मतलब डेवलपर के रूप में आपके लिए अधिक प्रोडक्टिविटी होगा।
- TypeScript आप को ES6 फीचर्स जैसे क्लासेज, मॉड्यूल, एरो फंक्शंस, टेंप्लेट लिटरल और भी बहुत कुछ का उपयोग करने की अनुमति देता है। इसका मतलब बेहतर कोड को ऑर्गेनाइज करने और लिखने के लिए आपके डिस्पोजल में अधिक टूल्स है।
अगर मैंने आपको अच्छे से कन्वेंस नहीं किया है या आप इस बारे में और अधिक जानना चाहते हैं कि TypeScript NativeScript के साथ डेवलप करने के लिए क्यों अच्छा है, तो आप TypeScript के साथ बेहतर NativeScript एप्स को डेवलप करें की जांच कर सकते हैं।
2. टूलींग
TypeScript द्वारा प्रदान करने वाले फीचर्स का पूरी तरह से लाभ उठाने के लिए, मेरा सुझाव है कि आप Visual Studio Code टेक्स्ट एडिटर का उपयोग करें। इसमें एक IntelliSense फीचर है जो TypeScript कोड लिखते समय स्मार्ट ऑटो-कंप्लीशन प्रदान करता है, या Git के साथ इंटीग्रेट होता है, और इसमें डिबग करने की क्षमताएं भी है।
सभी में अच्छा, एक NativeScript प्लगइन भी है जो NativeScript एप्लीकेशन डिवेलप करते समय आपको अधिक प्रोडक्टिव बना देगा। एक फीचर जो मुझे उपयोगी लगता है वह है एम्युलेटर इंटीग्रेशन। यह आपको एम्युलेटर को सीधे टेक्स्ट एडिटर से चलाने और ऐप को टेक्स्ट एडिटर से डीबग करने की अनुमति देता है। Visual Studio Code सभी प्रमुख प्लेटफार्म (Windows, Linux, OS X) पर उपलब्ध है और वह भी मुफ्त में।
हालांकि, यदि आप अपने टेक्स्ट एडिटर का कंफर्ट छोड़ने के लिए तैयार नहीं है, तो आप ऐसे एक्सटेंशन भी इंस्टॉल कर सकते हैं जो TypeScript के साथ कोडिंग को बेहतर बनाएंगे। Atom के लिए, atom-typescript प्लगइन है। Sublime Text के लिए, TypeScript Sublime प्लगइन है।
3. ऐप का ओवरव्यू
हम जिस ऐप को बनाने जा रहे हैं, वह एक मौसम की ऐप है। इसमें निम्नलिखित पेजेस होंगे:
- एक मुख्य पेज जो इस समय के मौसम के साथ साथ कुछ प्रासंगिक जानकारियां जैसे तापमान, वायु का दबाव और ह्यूमिडिटी को दर्शाता है।
- एक फोरकास्ट पेज जो पांच दिनों के फोरकास्ट को दर्शाता है कि अगले पांच दिनों के लिए मौसम कैसा रहने वाला है।
यहां देख सकते हैं कि पेज कैसा दिखेगा:



और यहां आप फोरकास्ट पेज को देख सकते हैं:



आप इसे ऐप के लिए इसके GitHub रेपो पर सारे सोर्स कोड को पा सकते हैं।
4. OpenWeatherMap
मौसम के डाटा OpenWeatherMap API से आएगा, और किसी भी अन्य API की तरह, आपको इसे उपयोग करने के लिए एक API key के लिए account साइन अप करने की जरूरत होगी। आगे बढ़ो और एक अकाउंट के लिए साइन अप करें। एक बार लॉगइन करने के बाद, API keys पेज पर जाएं, key फील्ड की वैल्यू कॉपी करें, और इसे कहीं भी सुरक्षित रख ले। एक बार ऐप बनने के बाद आपको इसकी जरूरत पड़ेगी।



5. ऐप को बनाना
अब जब आप जानते हैं कि ऐप कैसा दिखेगा, यह वास्तव में इसे बनाना शुरू करने का सही समय है। एक नया NativeScript प्रोजेक्ट बनाकर शुरू करें जो TypeScript टेंपलेट का उपयोग करता हो:
tns create weatherApp --template typescript
एक बार ऐसा करने के बाद, app
फोल्डर में नेविगेट करें और निम्नलिखित फोल्डर और फाइल बनाएं। अपनी सुविधा के लिए, आप GitHub रेपो को डाउनलोड या क्लोन कर सकते हैं और app
फोल्डर से फाइलों को कॉपी कर सकते हैं।
- common + constants.ts + navigation.ts + requestor.ts + utilities.ts - fonts - pages + forecast * forecast.css * forecast.ts * forecast.xml * forecast-view-model.ts + main * main.css * main.ts * main.xml * main-view-model.ts - stores + location.ts - app.css - app.ts
हम केवल app
डायरेक्टरी के अंदर ही काम करेंगे, इसलिए हर बार जब मैं किसी फाइल पाथ या फोल्डर का रेफरेंस लेता हूं, तो मान ले की app
डायरेक्टरी रुट है।
डिपेंडेंसीज को इंस्टॉल करें
एप्लीकेशन को डिपेंडेंसी के एक जोड़े की आवश्यकता है: NativeScript Geolocation Module और Moment। आप निम्न कमांड के साथ Geolocation मॉड्यूल को इंस्टॉल कर सकते हैं:
tns plugin add nativescript-geolocation
और इसके साथ Moment इंस्टॉल करें:
npm install moment
Geolocation मॉड्यूल का उपयोग यूज़र के वर्तमान लोकेशन को निर्धारित करने के लिए किया जाता है। Moment यूनिक्स टाइमस्टैंप के आसान फॉर्मेटिंग की अनुमति देता है, जिसे बाद में API से प्राप्त करेंगे।
कॉमन मॉड्यूल
इससे पहले कि हम ऐप की हर एक पेज के लिए कोड पर नजर डालें, आइए सबसे पहले कस्टम माड्यूल पर एक नजर डालते हैं जो पूरे ऐप में उपयोग किया जाएगा।
Constants
constants मॉड्यूल (common/constants.ts
) में पूरी एप्लीकेशन में उपयोग की जाने वाली सभी कांस्टेंट वैल्यू शामिल है: चीजें जैसे OpenWeatherMap API का बेस URL, API key जिसे अपने पहले प्राप्त किया था, एंड-पॉइंट की तरफ इशारा करता पाथ जिसका हम प्रयोग करेंगे, मौसम वाले आइकंस के करैक्टर कोड, और हवा की दिशा।
export const WEATHER_URL = 'http://api.openweathermap.org/data/2.5/'; export const WEATHER_APIKEY = 'YOUR OPENWEATHERMAP API KEY'; export const CURRENT_WEATHER_PATH = 'weather/'; export const WEATHER_FORECAST_PATH = 'forecast/daily/'; export const WEATHER_ICONS = { day: { 'clear': 0xf00d, 'clouds': 0xf002, 'drizzle': 0xf009, 'rain': 0xf008, 'thunderstorm': 0x010, 'snow': 0xf00a, 'mist': 0xf0b6 }, night: { 'clear': 0xf02e, 'clouds': 0xf086, 'drizzle': 0xf029, 'rain': 0xf028, 'thunderstorm': 0xf02d, 'snow': 0xf02a, 'mist': 0xf04a }, neutral: { 'temperature': 0xf055, 'wind': 0xf050, 'cloud': 0xf041, 'pressure': 0xf079, 'humidity': 0xf07a, 'rain': 0xf019, 'sunrise': 0xf046, 'sunset': 0xf052 } }; export const WIND_DIRECTIONS = [ "North", "North-northeast", "Northeast", "East-northeast", "East", "East-southeast", "Southeast", "South-southeast", "South", "South-southwest", "Southwest", "West-southwest", "West", "West-northwest", "Northwest", "North-northwest" ];
Utilities
Utilities मॉड्यूल में सभी प्रकार के यूटिलिटी फंक्शन शामिल है: दिशाओं की डिग्रीओं को कन्वर्ट करना, हवा के गति के लिए एक वर्णनात्मक टेक्स्ट का निर्धारण (determine) करना, Kelvin को Celsius में परिवर्तित करना और कैरक्टर कोड को एक कैरक्टर में परिवर्तित करने जैसी चीजें। आप देखेंगे कि इन सभी फंक्शंस का उपयोग बाद में पेजो में कैसे किया जाता है।
import constants = require('./constants'); export function degreeToDirection(num) { var val= Math.floor((num / 22.5) + .5); return constants.WIND_DIRECTIONS[(val % 16)]; } export function describeWindSpeed(speed) { if(speed < 0.3) { return 'calm'; } else if(speed >= 0.3 && speed < 1.6) { return 'light air'; } else if (speed >= 1.6 && speed < 3.4) { return 'light breeze'; } else if (speed >= 3.4 && speed < 5.5) { return 'gentle breeze'; } else if (speed >= 5.5 && speed < 8) { return 'moderate breeze'; } else if(speed >= 8 && speed < 10.8) { return 'fresh breeze'; } else if(speed >= 10.8 && speed < 13.9) { return 'strong breeze'; } else if(speed >= 13.9 && speed < 17.2) { return 'moderate gale'; } else if (speed >= 17.2 && speed < 20.8) { return 'gale'; } else if (speed >= 20.8 && speed < 24.5) { return 'strong gale'; } else if (speed >= 24.5 && speed < 28.5) { return 'storm'; } else if (speed >= 28.5 && speed < 32.7) { return 'violent storm'; } else if (speed >= 32.7 && speed < 42) { return 'hurricane force'; } return 'super typhoon'; } export function describeHumidity(humidity) { if (humidity >= 0 && humidity <= 40) { return 'very dry'; } else if (humidity >= 40 && humidity <= 70) { return 'dry'; } else if (humidity >= 85 && humidity <= 95) { return 'humid'; } return 'very humid'; } export function describeTemperature(temp) { var celsius = convertKelvinToCelsius(temp); if (celsius >= 0 && celsius < 7) { return 'very cold'; } else if (celsius >= 8 && celsius < 13) { return 'cold'; } else if (celsius >= 13 && celsius < 18) { return 'cool'; } else if (celsius >= 18 && celsius < 23) { return 'mild'; } else if (celsius >= 23 && celsius < 28) { return 'warm'; } else if (celsius >= 28 && celsius < 32) { return 'hot'; } return 'very hot'; } export function convertKelvinToCelsius(celsius) { return celsius - 273.15; } export function getTimeOfDay() { var hour = (new Date()).getHours(); var time_of_day = 'night'; if(hour >= 5 && hour <= 18){ time_of_day = 'day'; } return time_of_day; } export function getIcons(icon_names) { var icons = icon_names.map((name) => { return { 'name': name, 'icon': String.fromCharCode(constants.WEATHER_ICONS.neutral[name]) }; }); return icons; }
Navigation
Navigation मॉड्यूल एक कस्टम हेल्पर मॉड्यूल है जो हमें ऐप के सभी पेजो के बीच आसानी से नेविगेट करने की अनुमति देता है। common/navigation.ts
फाइल को खोलें और उसमे निम्नलिखित कोड जोड़ें:
import frame = require('ui/frame'); export function getStartPage() { return 'pages/main/main'; } export function goToForecastPage() { frame.topmost().navigate('pages/forecast/forecast'); } export function goToMainPage() { frame.topmost().goBack(); }
यह ऐप में अन्य पेजेस पर नेविगेट करने के लिए Frame मॉड्यूल का उपयोग करता है। getStartPage()
मेथड केवल मुख्य ऐप पेज की लोकेशन रिटर्न करता है। goToForecastPage()
, जैसा कि नाम से पता चलता है, यूजर को फोरकास्ट पेज पर नेविगेट करने की अनुमति देता है।
NativeScript में नेविगेट करते समय, आपके पास इस बात का रेफरेंस होना चाहिए कि आप वर्तमान में कहां है। इसीलिए आपको सबसे पहले करंट या सबसे ऊपर वाला पेज प्राप्त करने के लिए topmost()
फंक्शन पर कॉल करना होगा, और फिर दूसरे पेज पर जाने के लिए navigate()
फंक्शन पर जाना होगा। यह फंक्शन उस पेज के पाथ को स्वीकार करता है जहां आप जाना चाहते हैं।
Requestor
Requestor
मॉड्यूल OpenWeatherMap API के लिए वास्तव में रिक्वेस्ट करता है। जैसे कि NativeScript आर्टिकल के इंट्रोडक्शन में उल्लेख किया गया है, NativeScript जावास्क्रिप्ट कोड को चलाने के लिए एक जावास्क्रिप्ट वर्चुअल मशीन का उपयोग करता है। इसका मतलब है कि हम उन फंक्शन को भी उपयोग कर सकते हैं जो ब्राउज़र में उपलब्ध है।
ऐसा ही एक फंक्शन fetch है, जो हमें रिमोट सर्वर से HTTP रिक्वेस्ट करने की अनुमति देता है। इसका पैरामीटर वह URL है जहां आप रिक्वेस्ट करना चाहते हैं। यह एक प्रॉमिस रिटर्न करता है ताकि हम then()
रॉ रिस्पांस का इंतजार करें। “raw” शब्द के उपयोग पर ध्यान दें; fetch
फंक्शन हैंडर्स के साथ रिस्पांस को रिटर्न करता है और साथ ही अन्य लो-लेवल इंफॉर्मेशन भी - इसलिए हमें वास्तविक JSON डाटा प्राप्त करने के लिए json()
फंक्शन को कॉल करने की आवश्यकता होती है। यह एक और प्रॉमिस लौट आएगा ताकि हम then()
वास्तविक ऑब्जेक्ट प्राप्त करने के लिए एक बार और उपयोग करें।
export function get(url){ return fetch( url ).then(function(response){ return response.json(); }).then(function(json){ return json; }); }
वैकल्पिक रूप से, आप Http मॉड्यूल का उपयोग कर सकते हैं, जो NativeScript में HTTP रिक्वेस्ट बनाने का अधिक मजबूत तरीका है।
लोकेशन स्टोर
लोकेशन स्टोर लोकेशन की जानकारी के लिए स्टोरेज के रूप में कार्य करता है। यह हमें किसी भी फाइल से करंट लोकेशन को अपडेट करने और प्राप्त करने की अनुमति देता है जो इस मॉड्यूल को इंपोर्ट करती है।
export var location; export function saveLocation(loc) { location = loc; } export function getLocation() { return location; }
मुख्य पेज
अब ऐप के हर एक पेज के लिए कोड पर एक नजर डालने का सही समय है। लेकिन इससे पहले कि हम ऐसा करें, पहले एंट्री-प्वाइंट फाइल (app.ts
) को खोलें। यह ऐप के शुरुआती पेज को प्राप्त करने के लिए नेविगेशन मॉड्यूल का उपयोग करता है:
import application = require("application"); import navigation = require('./common/navigation'); application.mainModule = navigation.getStartPage(); application.start();
इसके बाद, pages/main/main.xml
फाइल को ब्रेकडाउन करें।
जब भी यूजर इस खास पेज पर नेविगेट करता है, तो हर बार TypeScript फाइल में समान नाम वाले फंक्शन को एग्जीक्यूट करने के लिए navigateTo
इवेंट का उपयोग किया जाता है। CSS क्लास भी TypeScript फाइल में डायनेमिक रूप से निर्धारित होती है।
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="{{ background_class }}"> ... </Page>
ScrollView
कॉम्पोनेंट का उपयोग सब कुछ लपेटने के लिए किया जाता है ताकि स्क्रीन के आकार को प्रदर्शित करने के लिए कंटेंट के बाहर जाने पर एक वर्टिकल स्क्रोल बाहर ऑटोमेटिकली जनरेट हो।
और क्योंकि हम रिमोट सर्वर से डाटा लोड करने जा रहे हैं, प्लेटफॉर्म के डिफॉल्ट लोडिंग एनीमेशन को दिखाने के लिए ActivityIndicator
कॉम्पोनेंट का उपयोग किया जाता है। इसके लिए आपको एक busy
एट्रिब्यूट को सप्लाई करने की जरूरत होती है, जो बुलियन वैल्यू को स्वीकार करता है जो कंट्रोल करता है कि एनिमेशन शुरू करना है या नहीं। डिफ़ॉल्ट रूप से, यह true
पर सेट होता है और केवल एक बार ऐप के सर्वर पर रिक्वेस्ट करने के बाद ही इसे false
अपडेट किया जाता है।
visibility
एट्रिब्यूट का उपयोग यह सुनिश्चित करने के लिए भी किया जाता है कि जब यह एनिमेट नहीं कर रहा हो तो कॉम्पोनेंट किसी भी स्थान को कंज्यूम नहीं करता है।
<StackLayout> <ScrollView> <ActivityIndicator busy="{{ is_loading }}" visibility="{{ is_loading ? 'visible' : 'collapsed' }}" /> <StackLayout visibility="{{ !is_loading ? 'visible' : 'collapsed' }}"> ... </StackLayout> </ScrollView> </StackLayout>
मुख्य कंटेंट के लिए, हमारे पास टॉप पर वर्तमान मौसम का सामान्य ओवरव्यू है और इसके नीचे डीटेल्स है। सामान्य ओवरव्यू वर्तमान मौसम, वर्तमान तापमान, मौसम का विवरण और लोकेशन का प्रतिनिधित्व करने वाला एक आइकन दिखाता है।
<Label text="{{ icon }}" class="icon" /> <Label text="{{ temperature }}" class="temperature" /> <Label text="{{ weather }}" class="weather" textWrap="true"/> <Label text="{{ place }}" class="place" textWrap="true"/>
विवरण के लिए, वर्तमान मौसम के बारे में जानकारी का एक पूरा गुच्छा है, जिसे आप संभवतः text
एट्रिब्यूट को देखकर अनुमान लगा सकते हैं। हर एक अपने स्वयं के आइकन के साथ भी है।
स्क्रीनशॉट पर जो मैंने आपको पहले दिखाया था, आपने देखा कि यह दोनों पेजेस के लिए दो-कॉलम का लेआउट उपयोग करता है। यही कारण है कि हम GridLayout
का उपयोग कर रहे हैं। लेकिन जैसा कि आप नीचे दिए गए कोड से देख सकते हैं, हम हर एक लाइन के पहले कॉलम के लिए एक GridLayout
का भी उपयोग कर रहे हैं।
आप पूछ सकते हैं कि हम ऐसा क्यों कर रहे हैं बजाय इसके कि सीधे तीन-कॉलम लेआउट बनाएं जिसमें पहले कॉलम में आइकन हो, दूसरे में वेदर अटरीब्यूट हो, और तीसरे में वैल्यू हो। यह पूरी तरह से समझने लायक है, और यह कोड को अधिक संक्षिप्त बना देगा।
लेकिन समस्या यह है कि NativeScript वर्जन 2.1 इस समय इसके GridLayout
के लिए परसेंटेज यूनिट की अनुमति नहीं देता है। इसका मतलब है कि हम आइकन के लिए 10%
जैसे कुछ का उपयोग नहीं कर सकते हैं जबकि अन्य दो कॉलम प्रत्येक 45% कंज्यूम करते हैं।
जिस लेआउट का उपयोग हमने नीचे किया है, वह उस समस्या के चारों ओर काम करता है, जो GridLayout
का उपयोग करके आइकन और वेदर एट्रिब्यूट को लगता है, जिसमें आइकन 30 पिक्सल का होता है और वेदर एट्रिब्यूट टेक्स्ट को समाहित (contain) करने के लिए जगह की उपलब्धता को कंज्यूम करता है। इस बात पर भी ध्यान दें कि GridLayout
पर row
और col
अटरीब्यूट का उपयोग किया जाता है।
<GridLayout columns="*,*" rows="auto,auto,auto,auto,auto,auto,auto" cssClass="details"> <GridLayout columns="30,auto" rows="auto" row="0" col="0"> <Label text="{{ wind_icon }}" class="small-icon" row="0" col="0" /> <Label text="Wind" textWrap="true" row="0" col="1" class="label" /> </GridLayout> <Label text="{{ wind }}" textWrap="true" row="0" col="1" /> <GridLayout columns="30,auto" rows="auto" row="1" col="0"> <Label text="{{ cloud_icon }}" class="small-icon" row="0" col="0" /> <Label text="Cloudiness" textWrap="true" row="1" col="1" class="label" /> </GridLayout> <Label text="{{ clouds }}" textWrap="true" row="1" col="1" /> <GridLayout columns="30,auto" rows="auto" row="2" col="0"> <Label text="{{ pressure_icon }}" class="small-icon" row="0" col="0" /> <Label text="Pressure" textWrap="true" row="2" col="1" class="label" /> </GridLayout> <Label text="{{ pressure }}" textWrap="true" row="2" col="1" /> <GridLayout columns="30,auto" rows="auto" row="3" col="0"> <Label text="{{ humidity_icon }}" class="small-icon" row="0" col="0" /> <Label text="Humidity" textWrap="true" row="3" col="1" class="label" /> </GridLayout> <Label text="{{ humidity }}" textWrap="true" row="3" col="1" /> <GridLayout columns="30,auto" rows="auto" row="4" col="0"> <Label text="{{ rain_icon }}" class="small-icon" row="0" col="0" /> <Label text="Rain" textWrap="true" row="4" col="1" class="label" /> </GridLayout> <Label text="{{ rain }}" textWrap="true" row="4" col="1" /> <GridLayout columns="30,auto" rows="auto" row="5" col="0"> <Label text="{{ sunrise_icon }}" class="small-icon" row="0" col="0" /> <Label text="Sunrise" textWrap="true" row="5" col="1" class="label" /> </GridLayout> <Label text="{{ sunrise }}" textWrap="true" row="5" col="1" /> <GridLayout columns="30,auto" rows="auto" row="6" col="0"> <Label text="{{ sunset_icon }}" class="small-icon" row="0" col="0" /> <Label text="Sunset" textWrap="true" row="6" col="1" class="label" /> </GridLayout> <Label text="{{ sunset }}" textWrap="true" row="6" col="1" /> </GridLayout>
मुख्य पेज के लिए अंतिम मार्कअप वह बटन है जो फोरकास्ट पेज पर जाता है:
<Button text="5 day Forecast" tap="goToForecastPage" />
मुख्य पेज जावास्क्रिप्ट
pages/main/main.ts
फाइल को खोलें और उसमे निम्नलिखित कोड को जोड़ें:
import { EventData } from "data/observable"; import { Page } from "ui/page"; import { MainViewModel } from "./main-view-model"; import navigation = require('../../common/navigation'); export function navigatingTo(args: EventData) { var page = <Page>args.object; page.bindingContext = new MainViewModel(); } export function goToForecastPage () { navigation.goToForecastPage(); }
ऊपर दिए गए कोड में, हम कुछ बिल्ट-इन NativeScript मॉड्यूस को इंपोर्ट करते हैं, मुख्य व्यू-मॉडल, और नेविगेशन।
EventData
ऑब्जेक्ट ऑब्जेक्ट डिस्ट्रक्टिंग का उपयोग करके एक्सट्रेक्ट किया जाता है, TypeScript द्वारा उपलब्ध कराया गया ES6 का फीचर। EventData
वह है जिसे हम navigationTo
फंक्शन के अरगुमेंट के रूप में पास करते हैं ताकि उसे किसी भी पेज द्वारा पास किसी भी डाटा तक पहुंच प्राप्त हो जो इस पेज पर नेविगेट करता है।
इसके पास एक object
प्रॉपर्टी होती है, जो मूल रूप से वह होती है जो कुछ भी कंपोनेंट इवेंट को ट्रिगर करता है। इस स्थिति में, हम जानते हैं कि यह Page
कंपोनेंट पर ट्रिगर किया जाता है, और इसीलिए हम <Page>
को एक type-assertion के रूप में प्रयोग करते हैं। उसके बाद, हम पेज पर मुख्य व्यू-मॉडल को बाइंड करते हैं। यह हमें क्लास में एक प्रॉपर्टी जोड़ने या अपडेट करने की अनुमति देगा, और यह तुरंत पेज पर दिखाई देगा।
मुख्य व्यू मॉडल (pages/main/main-view-model.ts
) में, पहले उन सभी मॉड्यूल को इम्पोर्ट करें जिनका हम उपयोग कर रहे हैं:
import observable = require("data/observable"); import requestor = require("../../common/requestor"); import constants = require("../../common/constants"); import geolocation = require("nativescript-geolocation"); import moment = require('moment'); import utilities = require('../../common/utilities'); import locationStore = require('../../stores/locationStore');
Observable मॉड्यूल को एक्सटेंड करके व्यू मॉडल बनाएं, जो इस क्लास के सभी प्रॉपर्टीज को ऑब्ज़र्व करने योग्य बनाता है। इसका मतलब यह है कि UI में प्रत्येक प्रॉपर्टी के लिए रेफरेंस हर बार इस क्लास में कुछ परिवर्तन होने पर अपडेट हो जाएंगे।
export class MainViewModel extends observable.Observable { constructor() { ... } }
कंस्ट्रक्टर के अंदर, यह जांच करें कि क्या जिओलोकेशन इनेबल है। अगर यह इनेबल नहीं है तो enableLocationRequest()
फंक्शन को कॉल करके इसे इनेबल करने का प्रयास करें। यह यूजर को जिओलोकेशन कोई इनेबल करने के लिए पूछने के लिए ऐप को ट्रिगर करता है।
super(); //call the constructor method of the parent class //check if geolocation is not enabled if (!geolocation.isEnabled()) { geolocation.enableLocationRequest(); //try to enable geolocation }
इसके बाद, यह निर्धारित करें कि यह दिन है या रात और परिणाम के अनुसार पेज का बैकग्राउंड सेट करें। इसके बाद पेज में आइकन सेट करें।
var time_of_day = utilities.getTimeOfDay(); this.set('background_class', time_of_day); this.setIcons();
उसके बाद, करंट लोकेशन निर्धारित करने का प्रयास करें। ध्यान दें कि यदि यूजर ने जिओलोकेशन की अनुमति नहीं दी है, तो ऐप बिल्कुल भी काम नहीं करेगा, क्योंकि मौसम यूजर की लोकेशन पर निर्भर करता है। ऐप 10 सेकंड में यूजर की लोकेशन को निर्धारित करने का प्रयास करेगा। यदि यह ऐसा करने में असफल रहता है, तो यूजर को एरर मैसेज दिखाया जाता है।
var location = geolocation.getCurrentLocation({timeout: 10000}). then( (loc) => { if (loc) { ... } }, (e) => { //failed to get location alert(e.message); } );
यदि लोकेशन रिक्वेस्ट सफल हो जाए, तो हम इसे locationStore
का उपयोग करके सेव करते हैं। यह हमें अन्य पेजेस पर बाद में दोबारा रिक्वेस्ट किए बिना लोकेशन तक पहुंचने की अनुमति देता है।
locationStore.saveLocation(loc);
आपके रेफरेंस के लिए, यहां एक सैंपल रिस्पांस है जो आपको NativeScript में लोकेशन को रिक्वेस्ट करते समय मिल सकता है। आप नीचे दिए गए प्रत्येक प्रॉपर्टी के बारे में अधिक जानने के लिए NativeScript के लोकेशन डॉक्यूमेंटेशन को देख सकते हैं।
{ "latitude":51.50853, "longitude":-0.12574, "altitude":0, "horizontalAccuracy":37.5, "verticalAccuracy":37.5, "speed":0, "direction":0, "timestamp":"2016-08-08T02:25:45.252Z", "android":{ } }
हम टेंप्लेट लिटरल्स का उपयोग करके पूरा API रिक्वेस्ट URL का निर्माण कर सकते हैं और Requestor मॉड्यूल का उपयोग करके रिक्वेस्ट कर सकते हैं।
this.set('is_loading', true); //show the loader animation var url = `${constants.WEATHER_URL}${constants.CURRENT_WEATHER_PATH}?lat=${loc.latitude}&lon=${loc.longitude}&apikey=${constants.WEATHER_APIKEY}`; requestor.get(url).then((res) => { ... });
एक बार जब कोई रिस्पांस वापस आता है, तो उसे एक्सट्रेक्ट करें और फॉर्मेट करें, और फिर परिणाम वाली वैल्यू को क्लास की प्रॉपर्टी के रूप में सेट करें। और क्योंकि क्लास observable है, यह ऑटोमेटिक रूप से ऐप के UI को अपडेट कर देगी।
this.set('is_loading', false); //stop loader animation var weather = res.weather[0].main.toLowerCase(); var weather_description = res.weather[0].description; var temperature = res.main.temp; var icon = constants.WEATHER_ICONS[time_of_day][weather]; var rain = '0'; if(res.rain){ rain = res.rain['3h']; } this.set('icon', String.fromCharCode(icon)); this.set('temperature', `${utilities.describeTemperature(Math.floor(temperature))} (${utilities.convertKelvinToCelsius(temperature).toFixed(2)} °C)`); this.set('weather', weather_description); this.set('place', `${res.name}, ${res.sys.country}`); this.set('wind', `${utilities.describeWindSpeed(res.wind.speed)} ${res.wind.speed}m/s ${utilities.degreeToDirection(res.wind.deg)} (${res.wind.deg}°)`); this.set('clouds', `${res.clouds.all}%`); this.set('pressure', `${res.main.pressure} hpa`); this.set('humidity', `${utilities.describeHumidity(res.main.humidity)} (${res.main.humidity}%)`); this.set('rain', `${rain}%`); this.set('sunrise', moment.unix(res.sys.sunrise).format('hh:mm a')); this.set('sunset', moment.unix(res.sys.sunset).format('hh:mm a'));
आपके रेफरेंस के लिए, यहां एक सैंपल रिस्पांस है जो API द्वारा रिटर्न किया जा सकता है:
{ "coord":{ "lon":-0.13, "lat":51.51 }, "weather":[ { "id":803, "main":"Clouds", "description":"broken clouds", "icon":"04d" } ], "base":"cmc stations", "main":{ "temp":291.44, "pressure":1031.7, "humidity":82, "temp_min":290.37, "temp_max":292.25 }, "wind":{ "speed":0.3, "deg":45, "gust":1 }, "rain":{ "3h":0.075 }, "clouds":{ "all":68 }, "dt":1470545747, "sys":{ "type":3, "id":1462694692, "message":0.0043, "country":"GB", "sunrise":1470544455, "sunset":1470598626 }, "id":2643743, "name":"London", "cod":200 }
आप वर्तमान मौसम डाटा के लिए डॉक्यूमेंटेशन में प्रत्येक प्रॉपर्टी के बारे में विस्तृत जानकारी पा सकते हैं।
आखिरकार। setIcons()
फंक्शन है, जो पेज में उपयोग किए जाने वाले सभी आइकन को सेट करता है:
setIcons() { var icons = utilities.getIcons([ 'temperature', 'wind', 'cloud', 'pressure', 'humidity', 'rain', 'sunrise', 'sunset' ]); icons.forEach((item) => { this.set(`${item.name}_icon`, item.icon); }); }
मुख्य पेज के स्टाइल और आइकन
यहां मुख्य पेज के लिए स्टाइल्स है:
.temperature { font-size: 40px; font-weight: bold; text-align: center; } .weather { font-size: 30px; text-align: center; } .place { font-size: 20px; text-align: center; } .icon { font-family: 'weathericons'; font-size: 100px; text-align: center; } .small-icon { font-family: 'weathericons'; font-size: 18px; margin-right: 5px; } .details { margin-top: 20px; padding: 30px; font-size: 18px; } .label { font-weight: bold; } .details Label { padding: 5px 0; } Button { margin: 20px; }
Icon
और small-icon
क्लासेज के लिए font-family
के रूप में weathericons
के उपयोग पर ध्यान दें। इस प्रकार हम NativeScript में आइकन फोंट का उपयोग करते हैं। यदि आप अपने पेजेस पर Font Awesome जैसे आइकन रखने के शौकीन है, तो आप उन्हें उसी तरह से उपयोग कर सकते हैं जैसे NativeScript एप्लीकेशन में।
सबसे पहले, आइकन फॉण्ट को डाउनलोड करें जिसे आप उपयोग करना चाहते हैं। इस ऐप के लिए Weather Icons Font का इस्तेमाल किया जाता है। जिप आर्काइव को एक्सट्रैक्ट करें और एक्सट्रैक्ट किए गए फोल्डर में font
डायरेक्टरी के अंदर जाएं। अपने ऐप में .ttf
फाइल को fonts
डायरेक्टरी में कॉपी करें और इसे weathericons.ttf
नाम दें। फाइल का नाम वह होगा जो आप उस विशिष्ट फॉण्ट आइकन का उपयोग करने के लिए हर बार font-family
के लिए वैल्यू के रूप में उपयोग करते हैं। इसके अलावा, आपको आइकन के आकार को नियंत्रित करने के लिए font-size
भी जोड़ना होगा।
फोरकास्ट पेज
अब हम फोरकास्ट पेज (pages/forecast/forecast.xml
) के लिए मार्कअप पर एक नजर डालते हैं। हेडर में, एक बैक बटन है जो यूजर को मुख्य पेज पर वापस जाने की अनुमति देता है। ध्यान दें की सामान्य उद्देश्य वाले Button
कॉम्पोनेंट के बजाय, हम एक NavigationButton
का उपयोग कर रहे हैं, जो की IOS बैक बटन और एंड्रॉयड नेवीगेशन बटन के NativeScript के बराबर है।
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="{{ background_class }}"> <Page.actionBar> <ActionBar title="5-day Forecast" class="header"> <NavigationButton text="Back" android.systemIcon="ic_menu_back" tap="goToMainPage" /> </ActionBar> </Page.actionBar> ... </Page>
मुख्य कंटेंट के लिए, उसी के सामान ListView
के बजाय Repeater
कॉम्पोनेंट का उपयोग किया जाता है। दोनों कंप्लेंट्स उपयोग लिस्ट बनाने के लिए किया जा सकता है, लेकिन ListView
अधिक घंटियां और सीटियों के साथ आते हैं। उदाहरण के लिए, यह ऑटोमेटिक से एक वर्टिकल स्क्रोलबार जनरेट करता है जब लिस्ट स्क्रीन के आकार से अधिक हो जाती है। इंफिनिटी स्क्रोलिंग फंक्शंस भी बिल्ट-इन है।
इस मामले में Repeater
कॉम्पोनेंट का उपयोग किया जाता है क्योंकि मेरे द्वारा बताए गए फीचर्स कि कोई वास्तविक आवश्यकता नहीं है। हमें बस जरूरत है एक बेयर-बोन लिस्ट की।
<StackLayout> <ScrollView> <ActivityIndicator busy="{{ is_loading }}" visibility="{{ is_loading ? 'visible' : 'collapsed' }}" /> <Repeater items="{{ forecast }}"> <Repeater.itemTemplate> ... </Repeater.itemTemplate> </Repeater> </ScrollView> </StackLayout>
प्रत्येक Repeater.itemTemplate
के अंदर दो कॉलम के साथ एक GridLayout
है, एक सामान्य मौसम की जानकारी के लिए और एक उसके विवरण के लिए।
पहला कॉलम एक StackLayout
है जिसमें दिनांक, मौसम का आइकन और मौसम की जानकारी है। दूसरों कॉलम भी एक StackLayout
है जिसमें चार GridLayouts
है जिनमें चार मौसम की विशेषताएं ( तापमान, हवा की गति, बादल और हवा का दबाव) शामिल होंगे।
पहले GridLayout
में आइकन, दिन का तापमान, और रात के तापमान को रखने के लिए तीन कॉलम है। अन्य तीन लाइन्स में केवल दो कॉलम है - आइकन के लिए और मौसम के एट्रिब्यूट की वैल्यू।
<GridLayout class="item" columns="*,*" rows="auto"> <StackLayout class="day-weather" row="0" col="0"> <Label text="{{ day }}" class="date" /> <Label text="{{ icon }}" class="icon" /> <Label text="{{ description }}" textWrap="true" /> </StackLayout> <StackLayout class="details" row="0" col="1"> <GridLayout columns="30,auto,auto" rows="auto" row="0" col="0"> <Label text="{{ $parents['Page'].temperature_icon }}" class="small-icon" row="0" col="0" /> <Label text="{{ temperature.day }}" class="temp day-temp" row="0" col="1" /> <Label text="{{ temperature.night }}" class="temp night-temp" row="0" col="2" /> </GridLayout> <GridLayout columns="30,auto" rows="auto" row="1" col="0"> <Label text="{{ $parents['Page'].wind_icon }}" class="small-icon" row="0" col="0" /> <Label text="{{ wind }}" row="0" col="1" /> </GridLayout> <GridLayout columns="30,auto" rows="auto" row="2" col="0"> <Label text="{{ $parents['Page'].cloud_icon }}" class="small-icon" row="0" col="0" /> <Label text="{{ clouds }}" row="0" col="1" /> </GridLayout> <GridLayout columns="30,auto" rows="auto" row="3" col="0"> <Label text="{{ $parents['Page'].pressure_icon }}" class="small-icon" row="0" col="0" /> <Label text="{{ pressure }}" row="0" col="1" /> </GridLayout> </StackLayout> </GridLayout>
$parents[‘Page’]
के उपयोग पर ध्यान दें। Repeater
या ListView
कॉम्पोनेंट का उपयोग करते समय, आपके पास उस ऐरे के बाहर डाटा तक पहुंच नहीं हो सकती है जिसे आपने लिस्ट के लिए उपयोग करने के लिए निर्देशित किया है - जब तक आप स्पष्ट रूप से पेरेंट कॉम्पोनेंट को निर्देश नहीं करते हैं जहां डाटा उपलब्ध है। यही वह जगह है जहां $parents[‘Page’]
आता है। $parents
NativeScript में एक विशेष वेरिएबल है जो आपको एक विशिष्ट कंपोनेंट पर उपलब्ध डाटा तक पहुंचने की अनुमति देता है। इस स्थिति में, हमने प्रत्येक मौसम के एट्रिब्यूट के लिए आइकन तक पहुंचने के लिए Page
निर्दिष्ट किया।
<GridLayout columns="30,auto" rows="auto" row="1" col="0"> <Label text="{{ $parents['Page'].wind_icon }}" class="small-icon" row="0" col="0" /> <Label text="{{ wind }}" row="0" col="1" /> </GridLayout>
फोरकास्ट पेज जावास्क्रिप्ट
फोरकास्ट पेज के लिए कोड मुख्य पेज के कोड के समान ही होता है। एकमात्र अंतर यह है कि नेविगेशन फंक्शन मुख्य पेज पर वापस जाने के लिए है, और हम ForecastViewModel
का उपयोग व्यू-मॉडल के रूप में कर रहे हैं।
import { EventData } from "data/observable"; import { Page } from "ui/page"; import { ForecastViewModel } from "./forecast-view-model"; import navigation = require('../../common/navigation'); export function navigatingTo(args: EventData) { var page = <Page>args.object; page.bindingContext = new ForecastViewModel(); } export function goToMainPage() { navigation.goToMainPage(); }
यहां व्यू मॉडल के लिए कोड है (pages/forecast/forecast-view-model.ts
):
import observable = require("data/observable"); import requestor = require("../../common/requestor"); import constants = require("../../common/constants"); import moment = require('moment'); import utilities = require('../../common/utilities'); import locationStore = require('../../stores/locationStore'); export class ForecastViewModel extends observable.Observable { constructor() { super(); var location = locationStore.getLocation(); var url = `${constants.WEATHER_URL}${constants.WEATHER_FORECAST_PATH}?cnt=6&lat=${location.latitude}&lon=${location.longitude}&apikey=${constants.WEATHER_APIKEY}`; var time_of_day = utilities.getTimeOfDay(); this.set('is_loading', true); this.set('background_class', time_of_day); this.setIcons(); requestor.get(url).then((response) => { this.set('is_loading', false); var forecast = this.getForecast(response); this.set('forecast', forecast); }); } private getForecast(response) { var forecast = []; var list = response.list.splice(1); //remove first item from array of forecasts //format and push all the necessary data into a new array list.forEach((item) => { forecast.push({ day: moment.unix(item.dt).format('MMM DD (ddd)'), icon: String.fromCharCode(constants.WEATHER_ICONS['day'][item.weather[0].main.toLowerCase()]), temperature: { day: `${utilities.describeTemperature(item.temp.day)}`, night: `${utilities.describeTemperature(item.temp.night)}` }, wind: `${item.speed}m/s`, clouds: `${item.clouds}%`, pressure: `${item.pressure} hpa`, description: item.weather[0].description }) }); return forecast; } private setIcons() { var icons = utilities.getIcons(['temperature', 'wind', 'cloud', 'pressure']); icons.forEach((item) => { this.set(`${item.name}_icon`, item.icon); }); } }
कंस्ट्रक्टर के अंदर, हम लोकेशन स्टोर से करंट लोकेशन को प्राप्त करते हैं और 16-day वेदर फोरकास्ट के लिए URL एंड प्वाइंट का निर्माण करते हैं। लेकिन 16 के बजाय, हम केवल पांच दिन चाहते हैं, इसीलिए हम काउंट (cnt
) के लिए 6 को निर्दिष्ट करते हैं। हम 6 का उपयोग करते हैं क्योंकि समय टाइम जोन पर निर्भर है और बताए गए स्थान पर नहीं है। इसका मतलब है कि संभावना होगी कि API पिछले दिन या वर्तमान दिन के लिए मौसम रिटर्न करेगा। इसीलिए 1 दिन अतिरिक्त है जो पैडिंग का काम करता है।
var location = locationStore.getLocation(); var url = `${constants.WEATHER_URL}${constants.WEATHER_FORECAST_PATH}?cnt=6&lat=${location.latitude}&lon=${location.longitude}&apikey=${constants.WEATHER_APIKEY}`;
इसके बाद, रिक्वेस्ट करें और getForecast()
फंक्शन को कॉल करके API रिस्पांस के साथ UI को अपडेट करें:
requestor.get(url).then((response) => { this.set('is_loading', false); var forecast = this.getForecast(response); this.set('forecast', forecast); });
यहां एक सिंपल रिस्पांस 16-day के फोरकास्ट एंडप्वाइंट द्वारा रिटर्न आ गया है। ध्यान दें कि सैंपल को अधिक संक्षिप्त बनाने के लिए, मैंने काउंट को 1 पर सेट किया है, यही कारण है कि list
प्रॉपर्टी में केवल एक ऑब्जेक्ट है।
{ "city":{ "id":2643743, "name":"London", "coord":{ "lon":-0.12574, "lat":51.50853 }, "country":"GB", "population":0 }, "cod":"200", "message":0.0347, "cnt":1, "list":[ { "dt":1470571200, "temp":{ "day":24.69, "min":17.37, "max":24.69, "night":17.37, "eve":23.29, "morn":19.02 }, "pressure":1029.77, "humidity":0, "weather":[ { "id":500, "main":"Rain", "description":"light rain", "icon":"10d" } ], "speed":8.27, "deg":253, "clouds":0 } ] }
फोरकास्ट पेज स्टाइल्स
यहां फोरकास्ट पेज के लिए स्टाइल्स है (pages/forecast/forecast.css
):
Page { font-size: 15px; } .item { padding: 20px 10px; } .day-weather { text-align: center; } .details { horizontal-align: left; } .date { font-size: 20px; } .icon { font-family: 'weathericons'; font-size: 30px; } .temp { padding: 3px; text-align: center; font-size: 15px; } .day-temp { background-color: #d0c110; } .night-temp { background-color: #505050; } .small-icon { font-family: 'weathericons'; margin-right: 5px; text-align: center; }
ग्लोबल ऐप स्टाइल्स
app.css
फाइल को खोलें और निम्नलिखित स्टाइल्स को उसमें जोड़ें:
.header { background-color: #333; color: #fff; } .day { background-color: #f48024; color: #fff; } .night { background-color: #924da3; color: #fff; }
6. डिफॉल्ट ऐप आइकन को बदलना
आप App_Resources
फोल्डर पर जाकर डिफॉल्ट ऐप आइकन को बदल सकते हैं। वहां आप Android और IOS फोल्डर को देख सकते हैं। Android के लिए, आप आइकन बदलने के लिए प्रत्येक फोल्डर में इमेज फाइल को बदल सकते हैं।
drawable-hdpi
drawable-ldpi
drawable-mdpi
IOS के लिए, यह Assets.xcassets/AppIcon.appiconset
फोल्डर के अंदर की इमेजेस है जिन्हें बदलना चाहते हैं।
यदि आप Android और IOS दोनों के लिए आसानी से आइटम बनाना चाहते हैं, तो MakeAppIcon को देखें। बस आइकन के रूप में उपयोग करने के लिए एक इमेज फाइल चुने, और यह ऑटोमेटिक रूप से Android और IOS दोनों के लिए विभिन्न आकारों में जनरेट कर देगा। फिर आप ऊपर बताए गए फोल्डर में जा सकते हैं। बस सुनिश्चित करें कि आप को सही आकार मिल गया है, और नाम और इमेजेस के समान ही है जिन्हें वह रिप्लेस करते हैं।
7. ऐप को चलाना
आप अपने डिवाइस या एम्युलेटर पर हमेशा की तरह निम्न tns
कमांड को एक्सेक्यूट करके इसे चला सकते हैं:
tns run {platform} tns livesync {platform} --watch
एकमात्र अंतर क्योंकि अब हम TypeScript का उपयोग कर रहे हैं वह यह है कि TypeScript फाइलों को जावास्क्रिप्ट में कंपाइल करने के लिए प्रत्येक टास्क की शुरुआत में एक अतिरिक्त कदम होगा। TypeScript की मजबूत टाइप-चेकिंग कार्य कुछ एरर को कैच करने के लिए सुरक्षा जाल का काम करती है, इससे पहले कि NativeScript ऐप को कंपाइल करें।
निष्कर्ष
इस ट्यूटोरियल में, आपने सीखा कि TypeScript लैंग्वेज का उपयोग करके NativeScript के साथ एक ऐप को कैसे बनाया जाए। विशेष रूप से, आपने निम्नलिखित कंसेप्ट को सीखा:
- संबंधित फाइलों को अपने स्वयं के फोल्डर में डाल कर अपने ऐप को स्ट्रक्चर करना।
- मॉड्यूल का उपयोग करके कोड फिर से उपयोग करना।
- ऐप के पेजेस के लिए डाटा और फंक्शनैलिटी प्रदान करने के लिए व्यू-मॉडल का उपयोग करना।
- जिओलोकेशन प्लगइन के साथ लोकेशन का पता लगाना।
- HTTP रिक्वेस्ट को करना।
- फ़ॉन्ट आइकन का उपयोग करना।
- पेजेस के बीच नेविगेट करना।
मैं NativeScript के साथ बहुत बढ़िया एप्लीकेशन डिवेलप करने में अपनी यात्रा जारी रखने के लिए कुछ रिसोर्सेज के साथ यही छोड़ता हूं:
- Google Play या App Store पर अपने NativeScript एप को पब्लिश करने के तरीके के बारे में गाइड को पढ़े।
- NativeScript न्यूजलेटर को सब्सक्राइब करें और NativeScript कम्युनिटी में क्या हो रहा है इसके बारे में अपडेट रहे।
- Awesome NativeScript, बहुत बढ़िया NativeScript लाइब्रेरीज, टूल्स, रिसोर्सेज और एप्लीकेशंस के कलेक्शन को देखें।
- TypeScript के साथ शुरू करने के बारे में हमारे Envato Tuts+ कोर्स को देखें।