1. ماهو الcallback hell،  جحيم الكولباك؟
    لا يوجد شيء مميز في الجافا سكربت يسمى بجحيم الكولباك ما هو الا تسميه لأمر ما قد يقع فيه المطور وهو طريقة كتابة كود حيث يحتوي على عدة دوال Asynchronous مترابطة مع بعضها، واحدة داخل الاخرى،  مثال:
     
    getData1(function(x){ getData2(x, function(y){ getData3(y, function(z){ ... }); }); });  
    والسبب في ذلك يعود لأن ناتج "results" كل دالة يعتمد على ما سبقتها.
     
    ملاحظة: كلمة asynchronous تعني أمر يحدث لاحقا << لا تركز على هالشي مو موضوعنا.
     
    جحيم الكولباك أمر ليس بجيد للكود، خصوصا في الحالات المعقدة التي تكون فيها دوال كثيرة مربوطه مع بعضها البعض وهنا قد يؤخر وقت انتهاء من التنفيذ و كمطور انت لا تريد ان تقع في هذه المشكلة, لحل مشكلة جحيم الكولباك، يستخدم المطورون إحدى مكتبات البرومس promises "الوعد، الوعود"، فالوعد دالة إما أن يتم العمل به fulfilled مع اظهار نتيجة الوعد value او رده rejected مع إظهار السبب error، وقد يكون الكود يحتوي على أكثر من وعد، واحد تلو الآخر.
     

     
    شخصيا لا اعتمد على الوعود في حل مشكلة جحيم الكولباك، عند التعامل مع قواعد البيانات MySQL رغم أنها الطريقة المثلى ولكن تتطلب الكثير مع الكود "وجهة نظر" و قد تواجهك مشاكل في أداء performance التطبيق بعد ذلك, استخدم طريقة أكثر بدائية و فعالة "تفي بالغرض" ، مبدأ الفكرة و طريقة عملها تتشابه كثيرا مع مبدأ عمل promises ولكن بكود أقل، سأرفق الطريقة مع المثال بالأسفل.
     
    للتعرف أكثر على جحيم الكولباك، سأعرض لكم مثال على التعامل مع قاعدة البيانات MySQL بالـ NodeJS وعمل اكثر من query وناتج كل query يعتمد على كل سبقتها.
    var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { var username = results[0].username; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } else { res.json(200, { error: 'no posts found' }); } }); } else { res.json(200, { error: 'no user found by ID 26' }); } }); });  
    للتخلص على مثل هذه المشاكل في حالة التعامل مع MySQL / MariaDB يكون بإسناد results كل عملية query في دالة مثلا
    var express = require("express"); var app = express(); var mysql = require('mysql'); var conn = mysql.createConnection({ host: 'localhost', user: 'me', password: 'secret', database: 'my_db' }); conn.connect(); // GET method route app.get('/user/posts', function (req, res) { /* http://www.example.com/user/posts?userId=26 */ var userId = req.query.userId; conn.query('SELECT username FROM users WHERE ID = ?', [userId], function (error, results, fields) { if (error) throw error; if (results.length) { setUsername(results[0].username); } else { res.json(200, { error: 'no user found by ID 26' }); } }); function setUsername(user) { var username = user; conn.query('SELECT * FROM posts WHERE post_by = ?', [username], function (error, posts, fields) { if (error) throw error; if (posts.length) { setPosts(posts, username); } else { res.json(200, { error: 'no posts found' }); } }); } function setPosts(po, user) { var posts = po; // po is the result of the prev query and it is an object it could be length of 1 or more doesn't matter var username = user; conn.query('SELECT * FROM users_addresses WHERE username = ?', [username], function (error, address, fields) { if (error) throw error; if (statistics.length) { res.json(200, { username: username, posts: posts, address: address }); } else { res.json(200, { error: 'no statistics found' }); } }); } });  
    أو بطريقة اخرى وهي عمل execution لكل query بطريقة parallel او series  بإستخدام مكتبة async
    /* Make Sure To Install async npm install async --save */ var async = require(“async”); // Parallel Method async.parallel([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 5 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } //Series Method async.series([ wait5SecondsAndReturn1, wait5SecondsAndReturn2 ], function (err, results){ //after 10 seconds, results will be [1, 2] }); function wait5SecondsAndReturn1(callback) { setTimeout(function(){ callback(null, 1); }, 5000); } function wait5SecondsAndReturn2(callback) { setTimeout(function(){ callback(null, 2); }, 5000); } // Another one async.series([ function(callback) { setTimeout(function() { console.log(“Task 1”); callback(null, 1); }, 300); }, function(callback) { setTimeout(function() { console.log(“Task 2”); callback(null, 2); }, 200); }, function(callback) { setTimeout(function() { console.log(“Task 3“); callback(null, 3); }, 100); } ], function(error, results) { console.log(results); });  
    وبذلك تستطيع التخلص من جحيم الكولباك بدون promises التي يلقى الكثير من المبرمجين المبتدأئين صعوبة في التعامل مع هذا النوع من الدوال.
     
    ملاحظات حول المثال السابق:
    الأخذ بالاعتبار جميع الشروط من ان هذا المستخدم user لدية احصائية مسجله و بوستات, ان لم يكن تستطيع التخلص من الشرط if(posts.length) لا يهم , بالتالي سيتم تمرير اوبجكت بدون قيم. بعض المبرمجين قد لا يتفق مع العملية, احترم ذلك ولكنها تفي بالغرض مع ES2015 و مايليه .. اسناد اوبجكت الى متغير يعطيه نفس قيمه الاوبجكت بشكل مباشر.
    مستوى المقال: مبتدئ
  2. لا يخفى على الجميع تفوق لغة الجافاسكربت في الاونه الاخيره " منذ مدة في الحقيقة " بعد ظهور كمية كبيرة وضخمه جدا من المكتبات و أُطُر العمل libraries/frameworks، هذا التضخم و النمو السريع في لغة الجافاسكربت سببت ارباك لكثير من المبرمجين الذين أصبحوا لا يعرفون من اين البداية لدراسة هذه الفريمووركس واين النهايه خصوصا مع وجود تشابه مابينها بسبب المنافسة، على سبيل المثال:
    AngularJS VueJS ReactJS  
    حيث يعد الإثنين أطر عمل Frontend، ومع التطور ظهر أطر عمل مساعدة لاطار عمل اساسي (ان صح التعبير بالعربي) "بطتنا بطت بطن بطتكم" مثل فريمورك ExpressJS المساعد لل Runtime Environment NodeJS حيث يعمل الإثنين في السيرفر وليس جهة المستخدم، وامثلة كثيرة اخرى لا يسعنا التطرق لهم ( يخرب بيتهم كل يوم شي جديد يطلع ويصدم اكثر من الي قبله ).

    في هذا الدرس سنقوم بعرض احد المكتبات المبرمجة بلغة الجافاسكربت "PressureJS" لعمل / لتطبيق فكرة الـ3D Touch الموجودة في اجهزة ابل الجديدة، والـ3D Touch هو عبارة عن الضغط بقوة اكثر من المعتاده على بعض الخيارات لإظهار خيارات اكثر او عمل، تفعيل event (حدث) معين.

    اولا: قم بتحميل المكتبه من خلال الضغط هنا


    او بإستخدام npm or bower.
    npm
    npm install pressure --save bower
    bower install pressure --save
    ثانيا: طرق استخدام المكتبة
    Example 1:
    <script src="/js/pressure.js"></script> <script src="/js/jquery.pressure.js"></script> Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } });

    Example 2:
    var Pressure = require('pressure'); Pressure.set('#id-name', { change: function(force){ this.innerHTML = force; } });

    كما هو موضح، التجربة ستكون على عنصر في الصفحة بدلالة الـId وهو id-name، تحتوي الدالة اعلاه على حدث event بإسم change تحمل متغير يسمى force، هذا الحدث change يستخدم لمعرفة التغير في قوة الضغط force على العنصر id-name ويكون المتغير force رقم مابين الصفر الى 1 كحد اقصى.

    ملاحظة: في المثال الذي سأطرحة حاليا، كلمة this ستنعني العنصر نفسه مثلا this.style.width
    Pressure.set('#element', { start: function(event){ }, end: function(){ // this is called on force end }, startDeepPress: function(event){ // this is called on "force click" / "deep press", aka once the force is greater than 0.5 }, endDeepPress: function(){ // this is called when the "force click" / "deep press" end }, change: function(force, event){ // this is called every time there is a change in pressure // force will always be a value from 0 to 1 on mobile and desktop }, unsupported: function(){ // NOTE: this is only called if the polyfill option is disabled! // this is called once there is a touch on the element and the device or browser does not support Force or 3D touch } });

    او عند استخدامك الـjQuery
    // Select Element By Id $('#element').pressure({ // events goes here }); // Select Element By Class $('.element').pressure({ // events goes here });
    لنستعرض الدالة اعلاة كل جزء على حدى:
    - يوجد 6 انواع من الأحداث events التي تعتمد عليها / تقدمها هذه المكتبه في كلاس Pressure وهم:
     حدث start: لمعرفة بدأ الضغط حدث end: لمعرفة انتهاء الضغط. حدث startDeepPress: اذا كانت قوة الضغط force اعلى من 0.5 وهي اعلى من نص القيمة العليا 1. حدث endDeepPress: عند الانتهاء من الضغط على العنصر وقيمة الضغط دخلت ضمن قيمة startDeepPress اي اعلى من 0.5. حدث change: وياخذ متغير force كما شرحناه بالاعلى، هذا الحدث سيستدعى دائما عند تغير قيمه الضغط مابين 0 و 1. حدث unsupported: اذا كان المتصفح او الجهاز لايدعم ال3D Touch.
    - الخيارات options، بالاضافة الى الاحداث والمتغيرات السابقة هناك ايضا متغير خارج دالة الset وهو عبارة عن اوبجكت اختياري يحتوي على عدة عناصر منها polyfill اما ان يكون true او false "يستخدم اذا كان المتصفح او الجهاز لايدعم ال3D Touch ،يكون true بشكل افتراضي.
    Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; }, unsupported: function(){ alert("Oh no, this device does not support pressure."); } }, {polyfill: false});
    - المتغير الثاني في الoptions هو polyfillSpeedUp عدد ms ويستخدم لتحديد سرعة الوصول من 0 الى 1، كل 1000 تساوي ثانية واحدة.
    Pressure.set('#example', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedUp: 5000}); // takes 5 seconds to go from a force value of 0 to 1 // only on devices that do not support pressure  
    - المتغير polyfillSpeedDown عكس SpeedUp تماما, الوقت بالميلي سكند ms لرجوع قيمة قوة الضغط من 1 إلى 0.
    Pressure.set('#polyfill-speed-down', { change: function(force, event){ this.innerHTML = force; } }, {polyfillSpeedDown: 2000}); // takes 2 seconds to go from a force value of 1 to 0 // only on devices that do not support pressure
    - المتغير only اما ان يكون mouse, touch or pointer وهذا يعني عند الضغط على العنصر المراد تطبيق الـ3D Touch عليه اما ان يكون من خلال الفأرة فقط، الضغط بالاصبع فقط او بالبوينتر فقط.
    // فقط بالفأرة Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'mouse'}); // فقط عند الضغط بالاصبع, اجهزة ابل Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'touch'}); // فقط بالبوينتر ديفايسس مثل اجهزة تابلت الواكوم Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {only: 'pointer'});
    - متغير preventSelect يعرفه الكثير بـpreventDefault. اما ان يكون true او false , قيمة المتغير تكون true افتراضيا وتستخدم لمنع العمل الافتراضي للعناصر.
    Pressure.set('#example',{ change: function(force, event){ console.log(force); }, }, {preventSelect: false});
    الجزء الأخير من PressureJS هو دالة لعمل Configuration عام تتشارك فيه جميع العناصر يحتوي على مجموعة من الخيارات التي تم شرحها في قسم Options مثلا.
    // These are the default configs set by Pressure Pressure.config({ polyfill: true, polyfillSpeedUp: 1000, polyfillSpeedDown: 0, preventSelect: true, only: null });  
    ولكن, تستطيع عمل override لهذه الاعدادات من خلال عمل دالة Pressure.set({...}); I وإسنادها إلى مجموعة عناصر او عنصر واحد بإستخدام الـId او الـClass.
    انتهى .. من لديه اسئلة يتفضل هنا او على حسابي في تويتر @AbdullaScript
    مستوى المقال: مبتدئ
  3. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
    ماهو ejs ؟ هو لغة قوالب صمم ليعمل من جهة الخادم تم بناءة من قبل Matthew Eernisse
    يتيح لك إستخدام لغة javascript داخل ملفات html بشكل شبيه جدًا بالـ PHP
     
    استخدامة مع إطار Express
    اول يجب ان تقوم بإضافة ejs لمشروعك بكتابة الأمر التالي
    npm install ejs من ثم تضيف الشفرة التالية لتطبيق express الخاص بك
    app.set('view engine', 'ejs'); من ثم إضافة الملفات الى مجلد views ويجب ان ينتهي الملف بالأمتداد ejs
    ولعمل رسم للملف بإستخدام الشفرة أستخدم
    .render(اسم الملف نص, المدخلات عنصر)
    مثال
    app.get('/', function(req, res) { // مع إستبدال index بإسم الملف res.render('index', {name:"عالم البرمجة"}); }); مثال لمشروع Express
    ملفات المشروع
    . ├── app.js ├── package.json ├── package-lock.json ├── node_modules ├── public │   └── images │   ├── normal.png │   └── transparent.png └── views ├── footer.ejs ├── header.ejs └── index.ejs  
    ملف app.js
    var express = require('express'); var app = express(); app.set('view engine', 'ejs'); app.use(express.static("public")); app.get('/', function(req, res){ var images = [ 'transparent.png','normal.png' ]; res.render('index', { imgs: images, name:"عالم البرمجة" }); }); app.listen(80,function(){ console.log('[info] متصل على المنفذ 80'); });  
    ملف view/header.ejs
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title><%= title %></title> </head> <body> <p>مرحبًا بالعالم</p> <ul> <li><%= name %></li> </ul>  
    ملف view/index.ejs
    <%- include('header', {title: "مثال عالم البرمجة"}) %> <ul> <% for(var i=0; i< 5; i++) {%> <li><%= i + 1 %></li> <% } %> </ul> <h1><%= name %></h1> <% imgs.forEach( (img) => { %> <img src="images/<%= img %>"/><br/> <% }); %> <%- include('footer') %>  
    ملف footer.ejs
    <h5>&copy; عالم البرمجة</h5> </body> </html>  
    بعد تشغيل التطبيق
    الناتج

     
    الأوسمة المخصصة لـ Ejs والدوال
    <% %> يقوم بتنفيذ شفرة الجافاسكربت التي بداخلة <%= %> يطبع النص الذي بداخلة ( يقوم بعمل html entities encode للأوسمة html ) <%- %> يقوم بطباعة النص الذي بداخلة كا HTML <%% يطبع '<%' بالنص الذي بداخلة متخطي عملية المعالجة %%> يطبع '%>' بالنص الذي بداخلة متخطي عملية المعالجة <%_ يقوم بحذف جميع المسافات الفارغة التي قبلة مع تنفيذ شفرة الجافاسكربت التي بداخلة _%> يقوم بحذف جميع المسافات الفارغة التي بعدة مع تنفيذ شفرة الجافاسكربت التي بداخلة  
    include(اسم الملف نص, المدخلات عنصر) يقوم بجلب ملف ejs بعد عملية المعالجة له باقي الدوال تجدها في ViewHelpers  
     
    صورة الغلاف منقولة من coligo.io
    مستوى المقال: مبتدئ
  4. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
    هذا الدرس سوف يشرح لك كيفية بناء مشروع في nativescript وايضًا اضافة المنصة المستهدفة android او ios
    وكذلك إستعراض التطبيق في الـEmulator والتعديل على تصميم التطبيق
     
    بناء مشروع nativescript core
    بعد الدخول للمجلد المراد اضافة ملفات المشروع اليه بواسطة الطرفية ( للينكس والماك تسمى terminal وللويندوز تسمى cmd )
    تكتب الامر التالي
    tns create HelloWorld ماذا يقصد بهذا الامر ؟
    tns هو اختصار لـ nativescript اما t فهو للتفريق بينه وبين NS الخاص بنظام IOS
    اما Create فاتعني "بناء" او "انشاء"
    و HelloWorld هو اسم التطبيق

     
    اما اذا كنت تريد ان تستخدم nativescript core مع typescript فابإمكانك بان تضيف العلم --tsc للقيام بإستخدام القالب الافتراضي بواسطة typescript
    tns create HelloWorld --tsc  
    بناء مشروع nativescript with angular
    لبناء مشروع nativescript مع اطار العمل angular يكفي بان تظيف العلم --ng للأمر وسوف تجده قام ببناء مشروع angular
    tns create HelloWorld --ng  
    سوف اكمل الشرح بمشروع nativescript core
     
    ما الملفات اللتي سوف يقوم بإضافتها المشروع ؟
    ├── app // مجلد التطبيق الاساسي │   ├── app.css // ملف css خاص بالتصميم يعمل في كافة صفحات التطبيق │   ├── app.js // ملف app المتحكم بكامل التطبيق ( n تحديد الصفحة الرائيسية للتطبيق وما الى ذلك n) │   ├── bundle-config.js │   ├── main-page.js // ملف جافاسكربت المتحكم بالصفحة main-page │   ├── main-page.xml // ملف xml المخصص لتصميم الواجهه للصفحة main-page │   ├── main-view-model.js │   ├── references.d.ts │   ├── package.json │   ├── App_Resources // سوف تجد هنا الملفات شعار التطبيق و splashscreen وملفات strings والكثير الخاصة بنظام android و ios │   │   ├── Android │   │   │   ├── AndroidManifest.xml │   │   │   ├── app.gradle │   │   │   ├── drawable-hdpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── drawable-ldpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── drawable-mdpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── drawable-nodpi │   │   │   │   └── splash_screen.xml │   │   │   ├── drawable-xhdpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── drawable-xxhdpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── drawable-xxxhdpi │   │   │   │   ├── background.png │   │   │   │   ├── icon.png │   │   │   │   └── logo.png │   │   │   ├── values │   │   │   │   ├── colors.xml │   │   │   │   └── styles.xml │   │   │   └── values-v21 │   │   │   ├── colors.xml │   │   │   └── styles.xml │   │   └── iOS │   │   ├── Assets.xcassets │   │   │   ├── AppIcon.appiconset │   │   │   │   ├── Contents.json │   │   │   │   ├── icon-29@2x.png │   │   │   │   ├── icon-29@3x.png │   │   │   │   ├── icon-29.png │   │   │   │   ├── icon-40@2x.png │   │   │   │   ├── icon-40@3x.png │   │   │   │   ├── icon-40.png │   │   │   │   ├── icon-60@2x.png │   │   │   │   ├── icon-60@3x.png │   │   │   │   ├── icon-76@2x.png │   │   │   │   ├── icon-76.png │   │   │   │   └── icon-83.5@2x.png │   │   │   ├── Contents.json │   │   │   ├── LaunchImage.launchimage │   │   │   │   ├── Contents.json │   │   │   │   ├── Default@2x.png │   │   │   │   ├── Default-568h@2x.png │   │   │   │   ├── Default-667h@2x.png │   │   │   │   ├── Default-736h@3x.png │   │   │   │   ├── Default-Landscape@2x.png │   │   │   │   ├── Default-Landscape@3x.png │   │   │   │   ├── Default-Landscape.png │   │   │   │   ├── Default.png │   │   │   │   ├── Default-Portrait@2x.png │   │   │   │   └── Default-Portrait.png │   │   │   ├── LaunchScreen.AspectFill.imageset │   │   │   │   ├── Contents.json │   │   │   │   ├── LaunchScreen-AspectFill@2x.png │   │   │   │   └── LaunchScreen-AspectFill.png │   │   │   └── LaunchScreen.Center.imageset │   │   │   ├── Contents.json │   │   │   ├── LaunchScreen-Center@2x.png │   │   │   └── LaunchScreen-Center.png │   │   ├── build.xcconfig │   │   ├── Info.plist │   └   └── LaunchScreen.storyboard ├── platforms // هنا المنصات ├── package.json └── package-lock.json  
    اضافة منصة للمشروع
    لإضافة منصة للمشروع كل ماعليك هو الدخول لمجلد المشورع
    cd HelloWorld من ثم كتابة الامر التالي لإضافة منصة android
    tns platfrom add android او التالي لإضافة منصة ios
    tns platform add ios  
    بناء المشروع
    لبناء المشروع لـ android اكتب 
    tns build android او للبناء للـ ios اكتب
    tns build ios وسوف يبدا بعملية البناء مباشرة
     
    تعديل الصفحة الرائيسية
    لتعديل الصفحة الرائيسية تقوم بالتعديل على الملف main-page.xml و main-page.js المتواجدة في المجلد app
    <Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo" class="page"> <Page.actionBar> <ActionBar title="تطبيقي" icon="" class="action-bar"> <!-- تعديل هنا --> </ActionBar> </Page.actionBar> <StackLayout class="p-20"> <Label text="اضغط على الزر" class="h1 text-center"/> <!-- تعديل هنا --> <Button text="أضعط" tap="{{ onTap }}" class="btn btn-primary btn-active"/> <!-- تعديل هنا --> <Label text="{{ message }}" class="h2 text-center" textWrap="true"/> </StackLayout> </Page> var createViewModel = require("./main-view-model").createViewModel; // يستخدم الملف main-view-model للتحكم في binding الصفحة function onNavigatingTo(args) { var page = args.object; page.bindingContext = createViewModel(); // الأدراج هنا } exports.onNavigatingTo = onNavigatingTo; كما تلاحظ فهو يتسخدم الملف main-view-model للتحكم في binding الصفحة اذًا لنعدل عليه
    var Observable = require("data/observable").Observable; function getMessage(counter) { if (counter <= 0) { return "رائع! لقد حصلة على ميدالية الضاغط لـ nativescript!"; } else { return counter + " ضغطه متبقية"; } } function createViewModel() { var viewModel = new Observable(); viewModel.counter = 42; viewModel.message = getMessage(viewModel.counter); viewModel.onTap = function() { this.counter--; this.set("message", getMessage(this.counter)); } return viewModel; } exports.createViewModel = createViewModel; التطبيق بعد التعديل
        
     
    استعراض التطبيق في الـ Emulator او في هاتفك
    للأستعراض في جهاز قم فقط بتوصيل هاتفك بالحاسوب
    من ثم اكتب الامر التالي للأستعراض للـ android
    tns run android ونفس الامر من دون توصيل هاتفك بالجهاز للأستعراض في الـ Emulator
    ونفس الأمر للـ IOS فقط استبدل android بـ IOS

    سوف اقوم بشرح الامر tns run بالتفاصيل لاحقًا ان شاء الله
    مستوى المقال: مبتدئ
  5. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
     
    بعد المقدمة عن nativescript شرح اليوم لطريقة تثبيته
    تحتاج تثبيت nativescript على جهازك لتتمكن من إنشاء المشاريع الجديدة 
    وإستعراض وبناء تطبيق للمنصات الثلاث android و ios و windows phone
     
    المتطلبات
    android studio للبناء للـ android XCode ( يتطلب نظام ماك ) للبناء لنظام IOS محلي
    ليس بالضروره تحتاج XCode بإمكانك إستخدام Nativescript Sidekick للبناء لنظام IOS ( لكن يلزمك حساب مطور لعمل ذلك ) بإستخدام cloud build واستعراضة على جهازك بإستخادم QR Code 
    https://www.nativescript.org/nativescript-sidekick
    npm و node.js لتثبيت nativescript  
    خطوات التثبيت
    تثبيت node.js على جهازك وكذلك npm
    تثبيت nativescript وبعلم global لتستطيع إستخدامها عن طريق الطرفية
     
    تثبيت npm & node.js
    لأصحاب الويندوز والماك الطريقة سهلة جدًا
    كل ماعليك هو الولوج لموقع node.js وتحميلة البرنامج لنظامك
    nodejs.org/en/download
    ثم تضغط Download
     
     
    بعد تحميل الملف تتبع الخطوات التقليدية للتثبيت
    next > accept > next > install > close
    وتلقائيًا سوف يتثبت لديك npm مع node.js
     
    اما اذا كنت تملك لينكس فيمكنك تثبيت node.js و npm عن طريق الطرفية
    sudo apt-get install -y nodejs sudo apt-get install -y npm  
    تثبيت nativescript
    بواسطة الطرفية ( terminal في ماك ولينكس او cmd في ويندوز )
    قم بكتابة الامر التالي ( بصلاحية root في ماك ولينكس او الأداري في ويندوز )
    npm install -g nativescript  
    الان انت جاهز للتقدم في الدورة
    مستوى المقال: مبتدئ
  6. بسم الله الرحمن الرحيم
    السلام عليكم ورحمة الله وبركاته
    مقدمة عن إطار العلم nativescript
    ماهو nativescipt ؟
    nativescript مكتبة عمل مفتوحة المصدر لبناء تطبيقات الهواتف المحمولة بإستخدام native UI للجهاز المستهدف بكود واحد لجميع المنصات
    nativescript تم بناء من قبل شركة telerik المملوكة لشركة Progress ( الغنيتان عن التعريف )
     
    ماهي المنصات التي تستطيع البناء لها بواسطة nativescript ؟
    nativescript يستطيع البناء للمنصات التالية IOS و ANDROID و WINDOWS UWP بكود واحد
     
    ماهي اللغات التي يستخدمها nativescript ؟
    هناك مشروعان في nativescript
    الاول هو nativescript core
    ويستخدم XML و JavaScript أو Typescript و css أو sass
    والثاني المفضل لي هو nativescript with angular
    ويستخدم angular و typescript و css أو sass
     
    مالذي يميز nativescript عن المنصات الأخرى مثل react native و cordova و ionic ؟
    يختلف nativescript عن ionic و cordova و phonegap 
    بإنها تكنلوجيا مختلفة جدًا فهي تعمل في الوقت الحقيقي runtime
    وهي ليست تقنية web ولا تعمل داخل اطار ويب webview مثل تطبيقات cordova
    وايضًا nativescript و react native تستخدم native UI
    هذا سوف يعطيك اداء افضل
     
    وتمتاز nativescript عن react native بالوصول الكامل native apis
    اي بإمكانك كتابة كود java او objective c بإستخدام javascript فقط دون الحاجة الى بناء ملف jar وإضافته الى مشروعك
     
    مثال لكود objective c
    @interface NSObject + (instancetype)alloc; - (instancetype)init; @end @interface BaseClass : NSObject + (void)baseStaticMethod; - (void)baseInstanceMethod; @end @interface DerivedClass : BaseClass + (void)derivedStaticMethod; - (void)derivedInstanceMethod; @end تحويلة الى javascript
    function NSObject() { /* native call */ }; // Object.getPrototypeOf(NSObject) === Function.prototype NSObject.alloc = function () { /* native call */ }; // Object.getPrototypeOf(NSObject.prototype) === Object.prototype NSObject.prototype.init = function () { /* native call */ }; function BaseClass() { /* native call */ }; Object.setPrototypeOf(BaseClass, NSObject); BaseClass.baseStaticMethod = function () { /* native call */ }; BaseClass.prototype = Object.create(NSObject.prototype, { constructor: BaseClass }); BaseClass.prototype.baseInstanceMethod = function () { /* native call */ }; function DerivedClass() { /* native call */ }; Object.setPrototypeOf(DerivedClass, BaseClass); DerivedClass.derivedStaticMethod = function () { /* native call */ }; DerivedClass.prototype = Object.create(NSObject.prototype, { constructor: DerivedClass }); DerivedClass.prototype.derivedInstanceMethod = function () { /* native call */ };  
    هذا سوف يحل لك الكثير من المشاكل مثل إضافة لم تجدها ويريحك من بعض الإضافات الغير ضرورية
    ان شاء الله سوف احاول شرح طريقة التحويل من كود java او objective c الى javascript
     
    ما ميزات nativescript ؟
    * nativescript من الاصدار 3 واعلى تستطيع إستخدام جميع الـ packages في npm داخل تطبيقك
    * يستخدم javascript و css و xml ( لغات هيكله وتصميم وبرمجة مالوفة لمطوري الويب )
    * الوصول الكامل APIs للنظام المستهدف
    * بناء المشروع لثلاث منصات بكود واحد
    * يتوفر لديه مكتبة إضافات ضخمة plugins.nativescript.org
    * يتوفر لديه توثيق سهل ومبسط جدًا مع الامثلة بالصور والHكواد docs.nativescript.org مع API Reference
    * التحديث التلقائي للتطبيق في المستعرض بعد التعديل على الكود والحفظ دون الحاجة الى إعادة بناء التطبيق من جديد
     
    روابط خارجية:
    موقع nativescript: www.nativescript.org
    showcase لتطبقات تم إنشائها بواسطة nativescript: www.nativescript.org/showcases
     
    مستوى المقال: مبتدئ
  7. السلام عليكم ورحمة الله وبركاته..
     
    في هذا الدرس الثالث من دروس النود جي اس سنقوم بتعلم كيفية ضبط ويب سيرفر NGINX للعمل مع تطبيقات / مايكرو سيرفس الNodeJS و تحويل requests الى بورتات تطبيقاتك بشكل ضمني
     
    ماهو الnginx؟
    ببساطة هو بروكسي سيرفر عالي الاداء او ويب سيرفر،  بديل الapache.
     
    في ماذا يستخدم؟
    يستخدم في ريفيرس بروكسي للبروتوكولات HTTP, HTTPS, SMTP, IMAP, POP3 و كذلك لعمل توازن الضغط على السيرفر مثلا عندما يكون هناك عدد كبير جدا من الrequests تستطيع توزيع هذه الطلبات بالupstream بين عدة بورتات في نفس السيرفر او سيرفر خارجي مثلا اذا كان التطبيق او الموقع مبرمج بالNodeJS.

     
    بالعربي: لا تحاتي بتعرف كلشي بعد شوي.
    اولا: تثبيت الويب سيرفر.
    لتثبيت الويب سيرفر nginx اتبع التعليمات / الخطوات التالية:
    افتح التيرمنال وقم بإيقاف الapache اذا كان مثبت sudo /etc/init.d/apache stop حدث sudo apt-get update ثبت sudo apt-get install nginx تأكد ان الويب سيرفر يعمل sudo /etc/init.d/nginx status  
    ملاحظة: مهم جدا ايقاف Apache قبل تثبيت Nginx
     
    ثانيا: تشغيل تطبيقك الNode على الدومين الرئيسي.
    لتشغيل التطبيق عليك تحويل جميع الطلبات requests التي تأتي من العميل الى الPort الذي يعمل عليه التطبيق (3000 مثلا) عبر الويب سيرفر NGINX.

     
    ولعمل ذلك، افتح التيرمنال و قم بمتابعة هذه الاوامر
    اذهب لمجلد الويب سيرفر cd /etc/ngin/sites-available اكتب ls وسترى ملف بإسم default. افتح الملف للتعديل بإستخدام vim او nano وفي هذا الدرس سنستخدم الاول sudo vim default امسح كلشي واكتب هذا الكود server { listen 80 default_server; listen [::]:80 default_server; server_name www.example.com example.com; access_log /path/to/log/static_domain_access.log; location / { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:3000; proxy_redirect off; } }  
    اخيرا قم بإعادة تشغيل الويب سيرفر
     
    افتح المتصفح و اكتب موقعك http://www example.com
     
    Bonus
    إذا كان لديك تطبيق \ موقع كبير جدا او API و تريد عمل load balancing لتوزيع عمليه الطلبات في الصورتين ادناه الطريقة لذلك, لاحظ ان التطبيق يعمل على اكثر من بورت وكذلك الـproxy pass هو عباره عن اسم الـupstream .cluster
     
    تطبيق الNode

     
    كونفيقريشن الـNginx

    مستوى المقال: مبتدئ
  8. السلام عليكم و رحمة الله و بركاته ..
    عودة الى الجزء الاول، وضحت كيفية ارسال بيانات من تطبيق الNode الى Pug وكيفية استقبال البيانات في الطرف الاخر و عرضها.
     
    في هذا الدرس سنتعامل مع قاعدة البيانات ونرسل البيانات بطريقتين مختلفتين:
    سيتم ارسال جميع البيانات من احد الجداول الى الواجهة و سأعرض لكم طريقة التعامل مع هذا النوع من البيانات المرسله سننشأه items عباره عن json objects  وبعدها نرسلهم.  
    الطريقة الأولى:
    و بالحديث عن قواعد البيانات، سنستخدم قاعدة بيانات MySQL هذه المره ( الرجاء الرجوع للدرس الاول للحصول على كافة التجهيزات لهذا الدرس). / هنا , انشأ قاعدة بيانات بإسم company وجدول employees مثلا  ومن ثم اضف هذه المدخلات.
    -- phpMyAdmin SQL Dump -- version 4.5.4.1deb2ubuntu2 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generation Time: Jun 09, 2017 at 10:41 AM -- Server version: 5.7.18-0ubuntu0.16.04.1 -- PHP Version: 7.1.5-1+deb.sury.org~xenial+2 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `company` -- -- -------------------------------------------------------- -- -- Table structure for table `employees` -- CREATE TABLE `employees` ( `ID` int(11) NOT NULL, `name` text COLLATE utf8_unicode_ci NOT NULL, `position` text COLLATE utf8_unicode_ci NOT NULL, `office` text COLLATE utf8_unicode_ci NOT NULL, `age` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -- Dumping data for table `employees` -- INSERT INTO `employees` (`ID`, `name`, `position`, `office`, `age`) VALUES (1, 'Airi Satou', 'Accountant', 'Tokyo', 23), (2, 'Airi Satou', 'Accountant', 'Tokyo', 23), (3, 'Donna Snider', 'Customer Support', 'New York', 27), (4, 'Brenden Wagner', 'Software Engineer', 'San Francisco', 28), (5, 'Caesar Vance', 'Pre-Sales Support', 'New York', 23), (6, 'Cedric Kelly', 'Senior Javascript Developer', 'Edinburgh', 22), (7, 'Dai Rios', 'Personnel Lead', 'Edinburgh', 35); -- -- Indexes for dumped tables -- -- -- Indexes for table `employees` -- ALTER TABLE `employees` ADD PRIMARY KEY (`ID`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `employees` -- ALTER TABLE `employees` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;  
    افتح ملف app.js و انشأ هذا الاوبجكت لعمل connection بين التطبيق وقاعدة البيانات
    // connection var connection = mysql.createConnection({ host : 'localhost', user : '...', password : '...', database : 'db_name' });  
    بعد ذلك،  سنقوم بتعديل صفحة الـdetails في ملف app.js  - المسار الذي يعرض صفحة الـdetails  -  لعمل Selection query
    app.get('/details', function(req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results); res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: results }); }); }); الـsyntax بسيط جدا، اولا connection وهو متغير التوصيل مم ثم query ثابته بعد ذلك الكويري &nbsp;ومن ثم الارقيومنتس (لمعلومات اكثر تجدونها هنا https://github.com/mysqljs/mysql/blob/master/Readme.md )
     
    مخرجات اي query دائما ما يكون json object بالتالي متغير results هو عباره عن list of objects
    [ { "prop1":"value1", "prop2":"value2" }, { "prop1":"value3", "prop2":"value4" } ]  
    نرجع إلى ملف details.pug ونقوم بتعديل block الجدول إلى التالي
    table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age}  
    نلاحظ وجود الـfor loop و طريقة استقبال وعرض المعلومات بسطر واحد فقط و ترجمته حرفيا ان لكل موظف في اوبجكت الموظفين ( الذي ارسلناه من الـNode ) قم بعمل صف في الجدول واضف مابعده
    for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} td.dt-body-right.sorting_1 #{employee.age}  
    بهذا انتهينا من الجزء الأول للدرس وننتقل للجزء الثاني:
    هذا الجزء من الدرس يتعلق بكيفية عمل items بشكل تخصيصي .. ان ماذا لو انك لا تريد ان تضم عمر الموظف في جدول العرض؟ سنقوم بالتالي في ملف app.js و details.pug - وكلشئ آخر يبقى كما هو:
    //app.js app.get('/details', function (req, res) { connection.query('SELECT * From `employees`', function (error, results, fields) { if (error) { throw error; } else { console.log('The solution is: ', results); var employees_json = []; for (var index = 0; index < results.length; index++) { var item = { name: results[index].name, position: results[index].position, office: results[index].office } employees_json.push(item); } res.render('details', { title: 'Details - Pug ExpressJS NodeJS Tutorial', employees: employees_json }); } }); }); //details.pug table#example.display.nowrap.dataTable.dtr-inline.collapsed(cellspacing='0') thead tr(role='row') th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Name: activate to sort column ascending', style='width: 142px;') Name th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Position: activate to sort column ascending', style='width: 192px;') Position th.sorting(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Office: activate to sort column ascending', style='width: 89px;') Office //th.dt-body-right.sorting_asc(tabindex='0', aria-controls='example', rowspan='1', colspan='1', aria-label='Age: activate to sort column descending', style='width: 37px;', aria-sort='ascending') Age tfoot tr th(rowspan='1', colspan='1') Name th(rowspan='1', colspan='1') Position th(rowspan='1', colspan='1') Office th.dt-body-right(rowspan='1', colspan='1') Age tbody for employee in employees tr.odd(role='row') td #{employee.name} td #{employee.position} td #{employee.office} //td.dt-body-right.sorting_1 #{employee.age}  
     
    إضغط هنا لتحميل ملفات الدرس الثاني anwbh-app-lesson2.zip
    مستوى المقال: مبتدئ

  9. السلام عليكم و رحمة الله و بركاته..

    في هذا الموضوع سنتحدث عن عن علاقة إطار العمل ExpressJS مع الباترن NodeJS و كيفية عمل Pug as template engine 

    اولا: حتى لا تكون هناك امور مبهمه و ابعاد الغيوم التي تدور حول اذهان الكثير من يريد العمل او التوجه لهذا الباترن يجب عرض بعض من الحقائق:
    الـNodeJS ليست لغة جديدة .. انما بيئة مبرمجة بالـJS. هذه البيئه تعمل في جهة السيرفر. ان كنت مبرمج AngularJS or ReactJS ليس هناك سطر محدد تربط فيه بين تطبيقك الNode مع الفريموورك الذي تعمل به. طريقة الربط تكون من خلال HTTP requests. تستطيع التعامل مع قواعد البيانات المختلفه مباشره بالـNode مثل MySQL, MariaDB و اشهرهم في هذا المجال هي MongoDB.  
    نعود مرة اخرى للـExpressJS الذي هو يعتبر فريم وورك ابعد مما ان يقال عنه "مساعد" في تطبيقات الـNode.
    بإستخدام هذا الفريم وورك الذي يعمل كذلك في السيرفر،  يتم تسهيل العمل و كمية الكود في تطبيق الـNode  بشكل كبير جدا.
    مثال على تطبيق Node بإستخدام فريم وورك ExpressJS وسيتم شرح اجزائه جميعها
    var express = require('express'); var app = express(); app.get('/', function (req, res) {  res.send('Hello World!') }); app.listen(3000, function () {  console.log('Example app listening on port 3000!') });  
    اول سطرين استدعاء موديول الاكسبرس و من ثم دالة الاكسبرس في المتغير app الذي استخدمناه في صنع التطبيق.
     
    الشطر الثاني get هو عبارة عن نوع الـhttp request قد يكون GET, POST, DELETE, UPDATE etc ….
     
    بعد ذلك يأتي المسار - لتفاصيل اكثر حول هذا الجزء الرجاء زيارة الدرس السابق.
     
    نننقل الآن الى امر اخر في الـExpressJS وهو الـtemplating ( عمل الواجهات UI و استقبال البيانات المرسلة من  الـNode )
    لعمل الواجهات الديناميكيه يفضل استخدام محركات التمبليت التي تتوافق مع الاكسبرس وهي
    PUG - know as Jade Mustache EJS  
    و في هذا الدرس سنستخدم المحرك الاول لعمل صفحة ويب اعتيادية و اخرى ديناميكية, لصنع واجهة بمحرك التمبليت pug يجب عليك ان تتقن او ان تاخذ فكره عن هذا المحرك لتعرف كيفية كتابه الكود ومثال على ذلك
    doctype html html(lang='en') head title Jade script(type='text/javascript'). foo = true; bar = function () {}; if (foo) { bar(1 + 5) } body h1 Jade - node template engine #container.col p You are amazing p | Jade is a terse and simple | templating language with a | strong focus on performance | and powerful features.  
    يعادل في الHTML 
    <!DOCTYPE html> <html lang="en"> <head> <title>Jade</title> <script type="text/javascript"> foo = true; bar = function () {}; if (foo) { bar(1 + 5) } </script> </head> <body> <h1>Jade - node template engine</h1> <div id="container" class="col"> <p>You are amazing</p> <p> Jade is a terse and simple templating language with a strong focus on performance and powerful features. </p> </div> </body> </html>  
    لمعلومات اكثر حول اللغة اطلع على موقعهم الرسمي
     
    وبذلك سنقوم بإنشاء مجلدات ومستندات بهذه الطريقة

     
    حمل الـbootstrap وانقل كل من bootstrap.min.css إلى مجلد css , انقل bootstrap.min.js إلى مجلد js
     
    بعد ذلك إبدأ بتثبيت الـpackages التي سنعمل بها من خلال فتح الـterminal في مجلد myapp من خلال الاوامر التالية
    $ npm install express --save $ npm install cookie-parser --save $ npm install body-parser --save $ npm install mysql --save  
    افتح ملف التطبيق app.js وقم بإستدعاء هذه البكجات
    var express = require('express'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var mysql = require('mysql');  
    الآن نبدأ بإعداد config فريم وورك الـExpressJS مع cookie-parser body-parser ( سنستخدمهم لاحقا )
    var router = express.Router(); var app = express(); app.use(bodyParser.json({limit: "50mb"})); app.use(cookieParser()); var urlencodedParser = bodyParser.urlencoded({ extended: true, parameterLimit:50000 }); app.use("/", router);  
    نضيف امكانية استخدام ملفات الـcss, js , images etc من خلال استخدام الـmiddleware ـexpress static بإعطاء مسار وهمي لهذه الملفات
    app.use('/css', express.static(__dirname + '/public/css')); app.use('/js', express.static(__dirname + '/public/js'));  
    نرى وجود ملفات الـcss and js في مجلد public/css ولكن المسار الذي سنكتبه في الكود هو فقط css/ وليس بالضرورة ان يكون اسم المسار الوهمي ذو علاقه بالمسار الاساسي .. تستطيع ان تسميه مثلا sambosa/ و في الحقيقة هو public/css/ 
     
    تحديد نوع الـtemplate engine الذي سنستخدمه في هذا التطبيق مع تحديد مسار مجلد الـviews الذي يحتوي على صفحات الموقع او التطبيق
    app.set('views', __dirname + '/views'); app.set('view engine', 'pug');  
    بعد إنشاء ملفات الـpug في إحدى الخطوات السابقه , انسخ والصق كود الصفحتين index.pug and layout.pug details.pug كلن على حدى
    //layout.pug doctype html html head title= title script(src='https://code.jquery.com/jquery-3.2.1.min.js') link(rel='stylesheet', href='/css/bootstrap.min.css') script(src='/js/bootstrap.min.js') body nav.navbar.navbar-default .container .navbar-header button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar') span.sr-only Toggle navigation span.icon-bar span.icon-bar span.icon-bar a.navbar-brand(href='/') NodeJS #navbar.navbar-collapse.collapse ul.nav.navbar-nav li.active a(href='/') Home li a(href='/details') details li.dropdown a.dropdown-toggle(href='#', data-toggle='dropdown', role='button', aria-haspopup='true', aria-expanded='false') | Dropdown span.caret ul.dropdown-menu li a(href='#') Action li a(href='#') Another action li a(href='#') Something else here li.divider(role='separator') li.dropdown-header Nav header li a(href='#') Separated link li a(href='#') One more separated link block content //index.pug extends layout block content .container h1 #{msg} p #{username} , welcome to the first templating tutorial //details.pug extends layout block content .container .table-responsive h2 user table p This is all users we have so far table.table.table-bordered#example thead tr th Firstname th Lastname th Email tbody tr td John td Doe td john@example.com tr td Mary td Moe td mary@example.com tr td July td Dooley td july@example.com link(rel='stylesheet', type='text/css', href='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.css') script(type='text/javascript', src='https://cdn.datatables.net/v/dt/dt-1.10.15/datatables.min.js') script(). $(document).ready(function() { $('#example').DataTable(); }); ملاحظة: نستخدم extends layout  لكي لا نكرر الـhead في الصفحات الاخرى , مثل include في الـPHP ( في هذا الدرس ) - الاستخدام الحقيقي للـlayout هو تصميم شكل معين لصفحات معينه .. كـtemplate خاص مثلا - معلومات اكثر من خلال الرابط هنا
     
     
    الأن تم تجهيز المستوى الأول من التطبيق وهو الـconfigurations , ننتقل إلى النص الآخر وهو الـroutes . اولا  route الصفحة الرئيسية سيكون كالتالي
    app.get('/', function(req, res) { res.render('index', { title: 'Pug ExpressJS NodeJS Tutorial', username: 'abdulla', msg: 'Hey There!' }) });  
    نلاحظ ان مسار الـroute هو مجرد slash للامام .. بذلك يتم تحديد المسار الرئيسي للتطبيق, بعد ذلك res.render اي تعني response render حيث يقوم تطبيق الـNode بالأجابة من بعد عمل طلب request من طرف المستخدم , للتوضيح اكثر الـHTTP هو عباره عن بروتوكول طلب و اجابة وبذلك request and response - req, res فعند طلب العميل امر ما يجب عليه ان يحصل على شي ما في المقابل.
     
    و كما موضع في الدالة اعلاه ان الـresponse هو عباره عن عمل render لملف index.pug الموجود في مجلد views مع ارسال ثلاث متغيرات title, username and msg , و طريقة استقبال البيانات في الـpug هي كالتالي ( يوجد اكثر من طريقة )
    h1 #{username} p Welcome to #{title}  
    خطوة اخيره لتشغيل التطبيق يجب تحديد بورت معين ولنفترض 3000
    app.listen(3000, function() { console.log('The app is running http://localhost:3000'); });  
    افتح الـterminal داخل مجلد التطبيق myapp واكتب الامر التالي لتشغيل التطبيق
    node app.js  
    افتح المتطفح على المسار
     
    انتهى الدرس الاول .. تم من خلاله
    عمل configuration لتطبيق الـnode الذي سنستخدمه في الدروس القادمة تثبيت template engine و توصيله مع تطبيق الـNode ارسال بيانات من الـNode إلى pug  
    الدرس القادم سيكون هناك سنعرض لكم كيفية التعامل مع قواعد البيانات وإرسال المعلومات الى pug 
     
    للحصول على ملفات العمل تجدونهم في المرفقات, بعد تحميل الملف قم بفك الضغط انتقل إلى داخل المجلد واكتب الأمر التالي لتثبيت جميع الـpackages دفعة واحده
    $ npm install --save  
     
    أضغط هنا لتحميل ملفات العمل anwbh-app.zip
    موقع مساعد لتحويل كودات الـHTML إلى Pug 
    http://html2jade.org
    مستوى المقال: مبتدئ
  10. السلام عليكم ورحمة الله وبركاته
    من خلال الدرسين السابقين والملاحظات:
    ماهو الNode.js؟ الدرس الأول في الNode.js عمل تسجيل دخول
    ملاحظات في الـJQuery مع الـNode.js
     
    تم التعرف على الفرق بين الـNode.js والـPHP , ماهو سبب تفوق سرعة النود وماهو النود جي اس مجملا , كما تم طرح الدرس الأول عن كيفية عمل خاصية تسجيل الدخول و حفظ الكوكيز في المتصفح ومنها يكون:
    عمل كونكشن مع الداتا بيس ارسال البيانات من فورم , طريقة استقبال المعلومات المرسلة , وبشكل خاص في الـNode.js , التعامل مع الـCookies بعد تسجيل الدخول  ,كيفية التعامل مع البيانات من ومطابقتها مع قاعدة البيانات.  
    في هذا الدرس الثاني سيتم عمل خاصية البحث بالطريقة الاعتيادية اولا ومن ثم سيكون هناك درس آخر لتبيان التغييرات لعمل البحث بشكل حي Live.
     
    إذا, لنبدأ هذا الدرس حيث سأفترض اولا بأنك اتممت قراءة الدرس الأول وتطبيق الدرس الأول و فهم ملاحظات الـJQuery مع الـNode.js , سنبدأ بعمل ملف الـبحث ومثلا يكون كالتالي:
    <!DOCTYPE html> <html lang="en"> <head id="head"> </head> <script src='js/jquery.js'></script> <script src="js/head.layout.js"></script> <script src="js/search.js"></script> <body> <!--/.nav-start --> <!-- Navigation Goes Here --> <nav class="navbar navbar-default"> <script src="js/nav.js"></script> </nav> <!--/.nav-end --> <div class="container"> <div class="col-md-12"> <div class="col-md-3"> <form class="form-horizontal" action="/api/search" method="GET" id='searhform'> <div class="form-group"> <label for="search"><h4><i class="fa fa-search" id="spinning_animation"></i> Search Key</h4></label> <input name='search' id='search' class="form-control" class="form-control" /> </div> <div class="form-group"> <button type="submit" class="btn btn-primary"> Search</button> </div> </form> </div> </div> <div class="col-md-12"> <!-- Search Results --> <div id="search_results"></div> </div> </div> </body> </html>  
    والملف الآخر في مجلد js يحتوي على ajax لإرسال قيمة الـinput#search
    $(document).ready(function() { //Ajax Search $(document).on("submit","#searhform",function(e){ $("#search_results").empty(); $("#spinning_animation").removeClass("fa fa-search"); $("#spinning_animation").addClass("fa fa-circle-o-notch fa-spin"); var search = $("#search").val(); $.ajax({ type: "GET", url: "api/search", async:true, timeout: 500, data: {search:search}, success: function(response){ // $(".img-responsive").hide(); $("#spinning_animation").removeClass("fa fa-circle-o-notch fa-spin"); $("#spinning_animation").addClass("fa fa-search"); $.each( response, function( key, val ) { if(val.ID != null){ $("#search_results").append( "<div class='col-md-3 text-center'>"+ "<div class='box'>"+ "<h3>"+val.car_name+"</h3>"+ "<p>Brand: "+val.car_brand+"<p>"+ "<p>Model: "+val.car_model+"<p>"+ "</div>"+ "</div>" ); } else{ $("#spinning_animation").removeClass("fa fa-circle-o-notch fa-spin"); $("#spinning_animation").addClass("fa fa-search"); $("#search_results").html("<p style='color:red;'>No Results</p>"); } }); }, error: function(){ $("#spinning_animation").removeClass("fa fa-circle-o-notch fa-spin"); $("#spinning_animation").addClass("fa fa-search"); $("#search_results").html("<p style='color:red;'>Error In Request</p>"); } }); e.preventDefault(); }); });  
    البحث سيكون في قاعدة البيانات التي سبق وعملتها وللتأكد , هذه هي القاعدة والجدول الذي سنبحث فيه حيث يحتوي على car_name, car_model, car_brand, ID (Primary)
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; -- -- Table structure for table `cars` -- CREATE TABLE `cars` ( `ID` int(11) NOT NULL, `car_name` text NOT NULL, `car_brand` text NOT NULL, `car_model` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `cars` -- INSERT INTO `cars` (`ID`, `car_name`, `car_brand`, `car_model`) VALUES (1, 'Nissan Patrol', 'Nissan', 2016), (2, 'Camaro SS', 'Chevy', 2010), (3, 'Mustang', 'Ford', 2013), (4, 'S500', 'Mercedes', 2009), (5, '330i', 'BMW', 2014); -- ------------------------------------ -- -- Indexes for dumped tables -- -- -- Indexes for table `cars` -- ALTER TABLE `cars` ADD PRIMARY KEY (`ID`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `cars` -- ALTER TABLE `cars` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;  
    وبهذا تم الانتهاء من اعداد قاعدة البيانات, ملف الـsearch.html وكذلك Ajax لارسال قيمة البحث إلى الـserver.js , لننتقل إلى ملف الـserver.js ونضيف الـroute المسؤول عن استقبال قيمة متغير البحث, عمل اللازم و ارجاع الناتج بعد ذلك .. حيث سيكون كالتالي:
    var http = require('http'); var express = require("express"); var mysql = require('mysql'); var app = express(); app.use('/bootstrap', express.static(__dirname + '/bootstrap')); app.use('/css', express.static(__dirname + '/css')); app.use('/js', express.static(__dirname + '/js')); app.use('/images', express.static(__dirname + '/images')); app.use('/faawesome', express.static(__dirname + '/faawesome')); var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '', database : 'cars' }); app.get('/api/search', function (req, res) { var searchkey = req.query.search; console.log(JSON.stringify(searchkey, null, 4)); if(searchkey != ""){ connection.query('SELECT * FROM cars WHERE `car_name` LIKE ?',"%"+searchkey+"%", function(err, rows, fields) { if (err){ throw err; } else { if(rows.length > 0){ res.writeHead(200, {'Content-Type': 'application/json'}); console.log(JSON.stringify(rows, null, 4)); res.end(JSON.stringify(rows ,null, 4)); } } }); } else { res.send("Nothing"); } }); app.get('/',function(req,res){ res.redirect("/home"); }); app.get('/home',function(req,res){ res.sendFile(__dirname + "/home.html"); }); app.get('/search',function(req,res){ res.sendFile(__dirname + "/search.html"); }); app.listen(3000,function(){ console.log("Working on port 3000"); });  
    شرح: هنا نلاحظ الـRoute المسؤول عن استقبال قيمة متغير البحث
    app.get('/api/search', function (req, res) { var searchkey = req.query.search; console.log(JSON.stringify(searchkey, null, 4)); if(searchkey != ""){ connection.query('SELECT * FROM cars WHERE `car_name` LIKE ?',"%"+searchkey+"%", function(err, rows, fields) { if (err){ throw err; } else { if(rows.length > 0){ res.writeHead(200, {'Content-Type': 'application/json'}); console.log(JSON.stringify(rows, null, 4)); res.end(JSON.stringify(rows ,null, 4)); } } }); } else { res.send("Nothing"); } });  
    خطوة اخيرا , قم بتشغيل التطبيق من خلال الأمر
    node server.js  
    افتح المتصفح على الصفحة
    127.0.0.1:3000/search  
    الملفات المرفقة
    js/nav.js
    $(".navbar.navbar-default").append( "<div class='container'>"+ "<div class='navbar-header'>"+ "<button type='button' class='navbar-toggle collapsed' data-toggle='collapse' data-target='#navbar' aria-expanded='false' aria-controls='navbar'>"+ "<span class='sr-only'>Toggle navigation</span>"+ "<span class='icon-bar'></span>"+ "<span class='icon-bar'></span>"+ "<span class='icon-bar'></span>"+ "</button>"+ "<a class='navbar-brand home' href='home'>"+ "<img src='images/nodejs-logo.png' style='max-width:52px;height:auto;' class='hidden-xs'>"+ "<img src='images/nodejs-logo-small.png' class='visible-xs'><span class='sr-only'></span>"+ "</a>"+ "</div>"+ "<div id='navbar' class='collapse navbar-collapse'>"+ "<ul class='nav navbar-nav navbar-left' id='uls'>"+ "<li class='active'><a style='color: #FFF;'><i class='fa fa-home'></i> Home</a></li>"+ "<li><a href='about'><i class='fa fa-folder-open'></i> About</a></li>"+ "<li><a href='contact'><i class='fa fa-phone'></i> Contact</a></li>"+ "</ul>"+ "</div>"+ "</div>" );  
    js/head.layout.js
    // $(document).ready(function() { $("#head").append( "<meta charset='utf-8'>"+ "<meta http-equiv='X-UA-Compatible' content='IE=edge'>"+ "<meta name='viewport' content='width=device-width, initial-scale=1'>"+ "<title>Search / NodeJS Bootstrap 101</title>"+ "<link rel='stylesheet' href='bootstrap/css/bootstrap.css'>"+ "<link href='css/style.blue.css' rel='stylesheet' id='theme-stylesheet'>"+ "<link rel='stylesheet' href='faawesome/css/font-awesome.css' media='screen' title='Font Awesome'>"+ "<script src='js/jquery.form.js'></script>"+ "<script src='bootstrap/js/bootstrap.js'></script>" ); // });  
    مستوى المقال: متوسط

  11. .....
    بعد المقدمة عن باترن الـNode.js في المقال السابق سأقوم بشرح اهم الدروس التي لطالما  كانت اولى الخطوات المتبعه في جميع اللغات لمعرفة كيفية التعامل مع:
    قواعد البيانات. طريقة ارسال المعلومات من Form. طريقة استقبال المعلومات المرسلة. وبشكل خاص في الـNode.js , كيفية التعامل مع البيانات من ومطابقتها مع قاعدة البيانات. التعامل مع الـCookies بعد تسجيل الدخول.  
    في بداية هذا الدرس, سأفترض امرين الأول هو مسبقا بأنك قمت بتثبيت الـ Dependencies وهم:
    npm install mysql npm install express npm install cookie-parser  
    والثاني هو ان تكون لديك معرفة متوسطة مسبقة بلغة الـ javascript و jquery
     
    وبعد التأكد من التثبيت, اعمل قاعدة بيانات سواء كانت خارجية ام داخليةوستكون كالتالي مثلا:
    -- phpMyAdmin SQL Dump -- version 4.5.1 -- http://www.phpmyadmin.net -- -- Host: 127.0.0.1 -- Generation Time: Sep 09, 2016 at 11:50 PM -- Server version: 10.1.16-MariaDB -- PHP Version: 5.6.24 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `cars` -- -- -------------------------------------------------------- -- -- Table structure for table `cars` -- CREATE TABLE `cars` ( `ID` int(11) NOT NULL, `car_name` text NOT NULL, `car_brand` text NOT NULL, `car_model` int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `cars` -- INSERT INTO `cars` (`ID`, `car_name`, `car_brand`, `car_model`) VALUES (1, 'Nissan Patrol', 'Nissan', 2016), (2, 'Camaro SS', 'Chevy', 2010), (3, 'Mustang', 'Ford', 2013), (4, 'S500', 'Mercedes', 2009), (5, '330i', 'BMW', 2014); -- -------------------------------------------------------- -- -- Table structure for table `users` -- CREATE TABLE `users` ( `ID` int(11) NOT NULL, `username` text NOT NULL, `password` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `users` -- INSERT INTO `users` (`ID`, `username`, `password`) VALUES (1, 'androidworldbh', '123123'), (2, 'user2', 'bahrain'), (3, 'user3', '4567'); -- -- Indexes for dumped tables -- -- -- Indexes for table `cars` -- ALTER TABLE `cars` ADD PRIMARY KEY (`ID`); -- -- Indexes for table `users` -- ALTER TABLE `users` ADD PRIMARY KEY (`ID`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `cars` -- ALTER TABLE `cars` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6; -- -- AUTO_INCREMENT for table `users` -- ALTER TABLE `users` MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;  
    اسم قاعدة البيانات هو cars تحتوي على جدولين users,cars وكل جدول يحتوي على بيانات كما هو موضح في الكود السابق.
     
    بعد ذلك قم بعمل ملف اسمه ولنفترض server.js يحتوي على التالي وبالتفصيل سأقوم بعرض الملف .. في البداية نستدعي مانريد من Packages
    var http = require('http'); var express = require("express"); var cookieParser = require('cookie-parser'); var mysql = require('mysql'); var app = express();  
    نقوم بعمل الـRouting لنحدد للتطبيق المعني بالمتغير app كيفية استجابة طلب المتصفح ( العميل ) والـSyntax هو
    app.METHOD(PATH, HANDLER);  
    في ملف server.js ستقوم بإضافة
    app.use(cookieParser()); app.use('/bootstrap', express.static(__dirname + '/bootstrap')); app.use('/css', express.static(__dirname + '/css')); app.use('/js', express.static(__dirname + '/js')); app.use('/images', express.static(__dirname + '/images')); app.use('/faawesome', express.static(__dirname + '/faawesome'));  
    لتستطيع استخدام الملفات الـCSS & JS وكذلك الصور , ولنستهل ربط قاعدة البيانات بالتطبيق من خلال الكود التالي:
    var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '', database : 'cars' }); ملاحظة: تستطيع استدعاء المتغيرات السابقة من ملف خارجي وبالغالب يتم تسميته بـconfig.js يحتوي على جميع المتغيرات الثابته constants مثل متغيرات ربط قواعد البيانات او ماشابه ذلك ولكن في هذا المثال سنستعمل الطريقة الإعتيادية والمباشرة.
    وبهذا تم اعداد وربط قاعدة البيانات مع التطبيق, وبما ان هذا الدرس عبارة عن كيفية عمل تسجيل دخول سنقوم بكتابة كود الفورم  داخل ملف login.html ( وسأفترض مسبقا بأنك تعرف ذلك ):
    <div class="container"> <div class="card card-container"> <img id="profile-img" class="profile-img-card" src="images/nodejs-logo.png" /> <p id="profile-name" class="profile-name-card"></p> <form class="form-signin" action="/api/login" method="get" id="loginForm"> <span id="reauth-email" class="reauth-email"></span> <input type="text" id="username" class="form-control" placeholder="Username" name="username" required autofocus> <input type="password" id="password" class="form-control" placeholder="Password" name="password" required> <div id="remember" class="checkbox"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block btn-signin" type="submit">Sign in</button> </form> <a href="#" class="forgot-password" id="status"> Forgot the password? </a> </div> </div>  
    سكربت ارسال بيانات فورم تسجيل الدخول في ملف الـhtml سيكون:
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script> <script> $(document).ready(function() { $('#loginForm').submit(function() { $("#status").empty().text("loging in..."); $(this).ajaxSubmit({ error: function(xhr) { status('Error: ' + xhr.status); }, success: function(response) { console.log(response) if(response == 401){ $("#status").html("Error In Provided Info"); } else { window.location.href = '/home/'+response; } } }); return false; }); }); </script>  
    نعود مرة اخرى لملف server.js ونضيف routing الفورم الذي بدوره يستقبل بيانات الدخول وهم اسم المستخدم username والباسسورد password ويطابق ما تم ارساله من قبل المستخدم مع ماهو موجود في جدول Users في قاعدة البيانات
    app.get('/api/login', function (req, res) { var user_credentials = { username: req.query.username, password: req.query.password } connection.query('SELECT * FROM users WHERE `username` = ?',user_credentials.username, function(err, rows, fields) { if (err) throw err; if(rows.length > 0){ var userpass = rows[0].password; if(userpass == user_credentials.password){ console.log(JSON.stringify(user_credentials, null, 4)); res.send(user_credentials.username); } else { return res.json(401); console.log("password aint right"); } } }); });  
    هنا نلاحظ عدة امور اولها الميثود المستخدم في هذا الـrouting او الـcontroller كما يستميه البعض وهي GET , ذلك يعني انه يجب على ميثود الفورم الذي عملته ان يكون GET ليستقبل البيانات
    app.get  
    الملاحظة الثانية هي المتغيرين الأثنين وهم اسم المستخدم والباسسورد , تستطيع استخدامهم في الكود بشكل مباشر بهذه الطريقة
    var username = req.query.username var pssword = req.query.password  
    ولكن لسهولة التعامل قمنا بإضافتهم إلى متغير user_credentials بهذه الطريقة
    var user_credentials = { username: req.query.username, password: req.query.password }  
    ولأستدعاء اسم المستخدم مثلا:
    user_credentials.username  
    ولمعلومات طرق عمل الـqueries الرجاء زيارة الرابط التالي:
    https://www.npmjs.com/package/mysql
     
    الملاحظة الثالثة وهي rows.length , عند execute الكويري, البكج المستخدم بشكل مباشر يقوم بإرجاع عدة بيانات تستطيع الإطلاع عليها في الـconsole وإحدى هذه الأمور هي عدد الصفوف التي هي متطابقة مع الكويري
    connection.query('SELECT * FROM users WHERE `username` = ?',user_credentials.username, function(err, rows, fields) ...  
    وستكون بالعادة صف واحد, لذلك نضع شرط إذا كان عدد الصفوف المعنية بالكويري اكثر من صفر rows.length > 0 ذلك يعني بأن اسم المستخدم موجود في قاعدة البيانات ونطابق الـpassword كالتالي:
    if(rows.length > 0){ var userpass = rows[0].password; // الباسسورد الذي تم استخراجه من الصف المرجع من الكويري if(userpass == user_credentials.password){ console.log(JSON.stringify(user_credentials, null, 4)); res.send(user_credentials.username); } else { return res.json(401); console.log("password aint right"); } }  
    إذا كان كلمة المرور متطابقة, سنقوم بإرسال اسم المستخدم مرة اخرى لصفحة login.html لنرسلها إلى صفحة اخرى المعنية بحفظ الـcookies
    res.send(user_credentials.username);  
    او اذا كانت كلمة المرور غير متطابقة سنرسل json عبارة عن
    return res.json(401);  
    وفي ajax صفحة الـlogin.html
    success: function(response) { console.log(response) if(response == 401){ $("#status").html("Error In Provided Info"); // إذا كان الكود المسترجع هو 401 ذلك يعني بأن كلمة السر غير متطابقة } else { window.location.href = '/home/'+response; // خلاف ذلك, سنرسل اسم المستخدم إلى روتنج معني بحفظ اسم المستخدم في كوكيز } }  
    إذا كانت كلمات السر متطابقة, ميثود الـAjax ستقوم بتحويل المستخدم إلى Routing لحفظ اسم المستخدم في كوكيز , وكود الـRounting هو:
    app.get('/home/:user',function(req,res){ res.cookie('name', req.params.user).redirect('/home'); });  
    الذي بدوره يحفظ اسم المستخدم في كوكيز بعنوان name وبعد ذلك يحوله إلى صفحة الـhome.html
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Node.js Bootstrap 101</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"> <script src="/bootstrap/js/bootstrap.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script> <script type="text/javascript"> $.ajax({ type: "GET", url: '/api/cookies', success: function(response) { if(response != "undefined"){ $("#uls").append("<li><a href='logout'><i class='fa fa-lock'></i> Logout</a></li>"); $("#navbar").append("<ul class='nav navbar-nav navbar-right'><li><a href='#'><i class='fa fa-user'></i> Welcome Back. "+response+"</a></li></ul>") } else { window.location.href = '/login'; } }, error: function(){ window.location.href = '/login'; } }); </script> </head> <body> <nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Node.js</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav" id="uls"> <li class="active"><a href="#">Home</a></li> <li><a href="about">About</a></li> <li><a href="contact">Contact</a></li> </ul> </div> <!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="col-md-12"> <h1>Home Page</h1> <h3>Bootstrap & NodeJS</h3> </div> </div> </body> </html>  
    و لا تنسى كتابة routing صفحتي الlogin and home و كذلك اللسنر في ملف server.js
    app.get('/',function(req,res){ res.redirect("/home"); }); app.get('/home',function(req,res){ res.cookie('name', req.cookies.name).sendFile(__dirname + "/home.html"); }); app.get('/login',function(req,res){ res.sendFile(__dirname + "/login.html"); }); app.listen(3000,function(){ console.log("Working on port 3000"); });  
    وللتاكد بأنه تم حفظ اسم المستخدم سنعمل routing اخر وهو:
    app.get('/api/cookies', function (req, res) { if(res.cookie('name', req.cookies.name) != null){ res.send(req.cookies.name); } else { res.cookie('name', "undefined") return res.json(401); } });  
    او من خلال console متصفح chrome بكتابة
     
    وبهذا, تستطيع تشغيل التطبيق الآن من خلال كوماند:
    node server.js  
    و في المتصفح
    127.0.0.1:3000/home  
    مستوى المقال: متوسط
  12. ماهو الNode.js؟
    كثير ماسمع المطورين بهذا الإطار في الفتره الاخيره حيث حصد هذا الاطار على اهتمام الكثير من المبرمجين في مجال تطوير الويب  لما يقدمه من امور خرافيه نوعا ما و مستوى جديد كليا في هذا العالم.
     
    ال Node.js هو اطار عمل برمج العديد من وحداته Modules الأساسية بلغه الJavaScript تم تطويره  من قبل مبرمج امريكي يعيش في المانيا  يدعى ريان دال و السوبر فايز جوينت، و كان اول إطلاق لهذا الباترن في عام 2009.
     
    من المعروف بأن لغة الجافا سكربت هي لغة الClient Side، بمعنى ذلك انها لغة تعمل بجانب المستخدم وليس في السيرفر ولكن بعد تطوير ريان دال لهذا الباترن (النود جي اس) الذي يعمل بمحرك قوقل V8 والعديد من الlibraries الاخرى اصبح الامر اكثر تعقيدا من ذي قبل و تحول هذا الإطار بالعمل في السيرفر كمثل الPHP، بمعنى اخر، الNode.js اصبح إطار عمل Functionality حركية و ديناميكية بشكل تام بإمكانك التعامل مع قواعد البيانات وما الى ذلك من خلاله بكل سهوله.
     
    يستخدم إطار الNode.js لبرمجة تطبيقات الويب بالتحديد و المواقع بشكل عام، يعتمد في عمله على الevents او باللغة العربية تدعى ( المناسبات )  لذلك اي شي يحصل على السيرفر يقوم بإطلاق non-blocking event كل كونكشن جديد => fires event ، معلومات مرسله من فورم => fires event ، طلب بيانات من قاعدة البيانات من قبل المستخدم => fires event.

    عمليا، هذا يعني ان الموقع او التطبيق لا يمكن ان يتاخر بتنفيذ مناسبة event حتى لو دخله او استخدمه آلاف المستخدمين في نفس الوقت لان إطار ال Node.js برمج ليكون Non-Blocking بذلك الأوامر يتم تنفيذها بالتوازي بخلاف الPHP التي هي لغة block until completion اي ان الاوامر لايتم تنفيذها الا بتنفيذ ما سبق من اوامر وهذا هو الفرق الاكبر مابين PHP & Node.js وهذا هو سبب تميز إطار عمل النود وسبب السرعه الرهيبه في تنفيذ الاوامر.
     

     
    لتثبيت الإطار، قم بزيارة الموقع ادناه، يدعم الانظمة جميعها Windows, OSX & Linux
    https://nodejs.org/en/download/  
    امثلة: بعد التحميل والتثبيت، في هذا القسم سيتم وضع عدة امثلة لطريقة بدائية Hello World ومن ابسط الامثلة هو
    1- انشأ ملف بإسم hello.js و اكتب فيه التالي
    var http = require('http'); http.createServer(function (req, res) {     res.writeHead(200, {'Content-Type': 'text/plain'});     res.end('Hello World!'); }).listen(3000, '127.0.0.1');  
    2- افتح الterminal او cmd على الوندوز واكتب
    node hello.js
    بذلك، اصبح التطبيق يعمل على port 3000 كما هو محدد.
    3- افتح اي متصفح تستخدمه وادخل على الرابط
    http://127.0.0.1:3000  
    مثال آخر على كيفية التعامل مع Bootstrap & Node.js
    صفحة الHTML
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Node.js Bootstrap 101</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"> <script src="/bootstrap/js/bootstrap.min.js"></script> </head> <body> <nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Node.js</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Home</a></li> <li><a href="about">About</a></li> <li><a href="contact">Contact</a></li> </ul> </div> <!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="col-md-12"> <h1>Home Page</h1> <h3>Bootstrap & NodeJS</h3> </div> </div> </body> </html>  
    صفحة الAbout
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Node.js Bootstrap 101</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"> <script src="/bootstrap/js/bootstrap.min.js"></script> </head> <body> <nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Node.js</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li><a href="home">Home</a></li> <li class="active"><a href="#">About</a></li> <li><a href="contact">Contact</a></li> </ul> </div> <!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="col-md-12"> <h1>ِAbout Page</h1> <h3>Bootstrap & NodeJS</h3> </div> </div> </body> </html>  
    صفحة الContact
    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Node.js Bootstrap 101</title> <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css"> <script src="/bootstrap/js/bootstrap.min.js"></script> </head> <body> <nav class="navbar navbar-default"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">Node.js</a> </div> <div id="navbar" class="collapse navbar-collapse"> <ul class="nav navbar-nav"> <li><a href="home">Home</a></li> <li><a href="about">About</a></li> <li class="active"><a href="#">Contact</a></li> </ul> </div> <!--/.nav-collapse --> </div> </nav> <div class="container"> <div class="col-md-12"> <h1>Contact Page</h1> <h3>Bootstrap & NodeJS</h3> </div> </div> </body> </html>  
    قم بتثبيت Dependency Express
    npm install express --save  
    ملف الserver.js
    var express = require("express"); var app = express(); app.use('/bootstrap', express.static(__dirname + '/bootstrap')); app.get('/',function(req,res){ res.sendFile(__dirname + "/home.html"); }); app.get('/home',function(req,res){ res.sendFile(__dirname + "/home.html"); }); app.get('/about',function(req,res){ res.sendFile(__dirname + "/about.html"); }); app.get('/contact',function(req,res){ res.sendFile(__dirname + "/contact.html"); }); app.listen(3000,function(){ console.log("Working On Port 3000"); });  
    تأكد من وضعك ملفات الBootstrap في المسار التالي ( في مجلد اسمه bootstrap بجانب ملف السيرفر)
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css"> <script src="/bootstrap/js/bootstrap.min.js"></script>  
    خطوة اخير, قم بتشغيل السيرفر من خلال الأمر
    node server.js  
    افتح المتصفح على الرابط التالي
    http://127.0.0.1:3000  
    وهذا هي اولى الدروس في الNode.js ولاستخدامات اكثر، قم بزيارة رابط Github ادناه للحصول على tools مفتوحه المصدر.
    https://github.com/developerbh  
    إسأل ماشئت وسأحاول الأجابة ان شاء الله.
    مستوى المقال: مبتدئ

عالم البرمجة

عالم البرمجة مقالات برمجة و دورات مجانية لإحتراف البرمجة هدفنا تبسيط البرمجة ونشرها بيد الكل بشكل ممتع ومتطور ومحدث بإستمرار لمواكبة جديد تطورات البرمجة الحديثة و المتقدمة بدون مقابل