কীভাবে জাভাস্ক্রিপ্টে ডিওএম ডেটা বাইন্ডিং প্রয়োগ করবেন


244

এই প্রশ্নটি কঠোরভাবে শিক্ষামূলক হিসাবে বিবেচনা করুন। আমি এটি বাস্তবায়নের জন্য নতুন উত্তর এবং ধারণা শুনতে আগ্রহী

TL; ড

আমি কীভাবে জাভাস্ক্রিপ্টের সাথে দ্বি-নির্দেশমূলক ডেটা-বাইন্ডিং বাস্তবায়ন করব?

ডিওএম-তে ডেটা বাইন্ডিং

DOM- র সাথে আবদ্ধ ডেটা দ্বারা আমি উদাহরণস্বরূপ, aকোনও সম্পত্তি সহ একটি জাভাস্ক্রিপ্ট অবজেক্ট থাকা b। তারপরে একটি <input>ডিওএম উপাদান থাকা (উদাহরণস্বরূপ), যখন ডিওএম উপাদান পরিবর্তিত হয়, aপরিবর্তিত হয় এবং বিপরীত হয় (তার মানে, আমি দ্বিদ্বিতীয় ডেটা বাইন্ডিং বলতে চাই)।

এঙ্গুলারজেএস-এর চিত্রটি এখানে কী দেখায় তা এখানে দেওয়া হয়েছে:

দ্বিমুখী ডেটা বাঁধাই

সুতরাং মূলত আমার কাছে জাভাস্ক্রিপ্টের অনুরূপ:

var a = {b:3};

তারপরে একটি ইনপুট (বা অন্য ফর্ম) উপাদান যেমন:

<input type='text' value=''>

আমি ইনপুটটির a.bমান (উদাহরণস্বরূপ) এর মান হতে চাই এবং যখন ইনপুট পাঠ্য পরিবর্তন হয়, আমিও পরিবর্তন করতে চাই a.b। যখন a.bজাভাস্ক্রিপ্ট পরিবর্তন হয়, ইনপুট পরিবর্তন হয়।

প্রশ্নটি

এটি সাধারণ জাভাস্ক্রিপ্টে সম্পন্ন করার জন্য কিছু প্রাথমিক কৌশল কী কী?

সুনির্দিষ্টভাবে, আমি উল্লেখ করতে একটি ভাল উত্তর চাই:

  • কীভাবে বস্তুর জন্য বাঁধাই কাজ করবে?
  • ফর্মের পরিবর্তন শুনা কীভাবে কাজ করবে?
  • কেবলমাত্র টেমপ্লেট স্তরে এইচটিএমএল সংশোধন করা কি সহজ উপায়ে সম্ভব? আমি এইচটিএমএল নথিতে নিজেই বাঁধাইয়ের ট্র্যাক রাখতে চাই না তবে কেবল জাভাস্ক্রিপ্টে (ডিওএম ইভেন্ট এবং জাভাস্ক্রিপ্ট ব্যবহৃত ডোম উপাদানগুলির রেফারেন্স রেখে)।

আমি কি চেষ্টা করেছি?

আমি গোঁফের খুব ভক্ত তাই আমি এটিকে টেম্পলেট করার জন্য ব্যবহার করার চেষ্টা করেছি। তবে আমি মুশকিল এইচটিএমএল এইচটিএমএলকে স্ট্রিং হিসাবে প্রসেস করি তাই ডেটা বাঁধাই করে নিজেকে ডেটা বন্ডিং সম্পাদন করার চেষ্টা করার সময় আমি ইস্যুগুলিতে ছড়িয়ে পড়েছি যাতে ফলাফল পাওয়ার পরে আমার ভিউমোডলে থাকা অবজেক্টগুলি কোথায় আছে সে সম্পর্কে আমার কোনও রেফারেন্স নেই। এটির জন্য আমি ভাবতে পারি এমন একমাত্র কাজটি হ'ল এইচটিএমএল স্ট্রিংকে (বা তৈরি করা ডোম ট্রি) বৈশিষ্ট্যগুলি দিয়ে নিজেই পরিবর্তন করা হয়েছিল। কোনও ভিন্ন টেম্প্লেটিং ইঞ্জিন ব্যবহার করতে আমার আপত্তি নেই।

মূলত, আমি একটি দৃ feeling় অনুভূতি পেয়েছিলাম যে আমি বিষয়টি হাতে নিয়ে জটিল করছি এবং এর একটি সহজ সমাধান রয়েছে।

দ্রষ্টব্য: দয়া করে এমন উত্তর সরবরাহ করবেন না যা বাহ্যিক লাইব্রেরিগুলি ব্যবহার করে, বিশেষত হাজার হাজার কোডের লাইন ones আমি AngularJS এবং নকআউটজেএস ব্যবহার করেছি (এবং পছন্দ করি!)। আমি 'ফ্রেম ফ্রেম এক্স ব্যবহার করুন' আকারে সত্যই উত্তর চাই না। সর্বোত্তমভাবে, আমি এমন একজন ভবিষ্যতের পাঠক চাই যিনি দ্বি-দিকনির্দেশক ডেটা বাইন্ডিং নিজেকে কীভাবে প্রয়োগ করতে পারেন তা উপলব্ধি করতে কীভাবে অনেকগুলি ফ্রেমওয়ার্ক ব্যবহার করবেন তা জানেন না। আমি একটি সম্পূর্ণ উত্তর আশা করি না , কিন্তু এক যে ধারণা পেতে পারে।


2
আমি ক্রেজিগ্লুকে বেনিয়ামিন গ্রুইনবাউমের নকশার উপর ভিত্তি করে তৈরি করেছি । এটি নির্বাচন, চেকবক্স এবং রেডিও ট্যাগগুলি সমর্থন করে। jQuery একটি নির্ভরতা।
জনএসজেড

12
এই প্রশ্নটি সম্পূর্ণ দুর্দান্ত। এটি যদি কখনও অফ-টপিক বা অন্য কোনও বোকামি থাকার কারণে বন্ধ হয়ে যায়, তবে আমি গুরুত্ব সহকারে তাড়িয়ে চলেছি।
ওসিডিভ

@ জনসজ আপনার ক্রেজিগ্লু প্রকল্পের উল্লেখ করার জন্য ধন্যবাদ thanks আমি দীর্ঘদিন ধরে একটি সাধারণ 2 ওয়ে ডেটা বাইন্ডার সন্ধান করছি। দেখে মনে হচ্ছে আপনি অবজেক্ট.ওবজার ব্যবহার করছেন না তাই আপনার ব্রাউজার সমর্থনটি দুর্দান্ত হওয়া উচিত। এবং আপনি গোঁফ টেম্প্লেটিং ব্যবহার করছেন না তাই এটি নিখুঁত।
গাভিন

@ বেঞ্জামিন আপনি কী শেষ করেছেন?
জননি

@ জোহনি আমার মতে সঠিক পন্থাটি হ'ল জেএস-এ ডিওএম তৈরি করা (প্রতিক্রিয়াটির মতো) এবং বিপরীতে নয়। আমি মনে করি যে শেষ পর্যন্ত আমরা কি করব।
বেনিয়ামিন গ্রুইনবাউম

উত্তর:


106
  • কীভাবে বস্তুর জন্য বাঁধাই কাজ করবে?
  • ফর্মের পরিবর্তন শুনা কীভাবে কাজ করবে?

একটি বিমূর্ততা যা উভয় বস্তুকে আপডেট করে

আমি মনে করি অন্যান্য কৌশল আছে, তবে শেষ পর্যন্ত আমার কাছে এমন একটি জিনিস থাকবে যা সম্পর্কিত ডিওএম উপাদানটির রেফারেন্স রাখে এবং একটি ইন্টারফেস সরবরাহ করে যা তার নিজস্ব ডেটা এবং তার সাথে সম্পর্কিত উপাদানগুলির আপডেটের সমন্বয় করে।

এর .addEventListener()জন্য এটি একটি খুব সুন্দর ইন্টারফেস সরবরাহ করে। আপনি এটিকে এমন একটি বস্তু দিতে পারেন যা eventListenerইন্টারফেসটি কার্যকর করে এবং এটি হ্যান্ডলারগুলিকে সেই বস্তুর সাথে thisমূল্য হিসাবে ডাকে ।

এটি আপনাকে উপাদান এবং এর সাথে সম্পর্কিত ডেটা উভয়টিতে স্বয়ংক্রিয় অ্যাক্সেস দেয়।

আপনার অবজেক্টের সংজ্ঞা দেওয়া হচ্ছে

প্রোটোটাইপাল উত্তরাধিকার হ'ল এটি বাস্তবায়নের একটি দুর্দান্ত উপায়, যদিও অবশ্যই প্রয়োজন নেই। প্রথমে আপনি এমন একটি কনস্ট্রাক্টর তৈরি করতে চান যা আপনার উপাদান এবং কিছু প্রাথমিক ডেটা গ্রহণ করে।

function MyCtor(element, data) {
    this.data = data;
    this.element = element;
    element.value = data;
    element.addEventListener("change", this, false);
}

সুতরাং এখানে কনস্ট্রাক্টর নতুন বস্তুর বৈশিষ্ট্যগুলির উপাদান এবং ডেটা সংরক্ষণ করে। এটি changeপ্রদত্ত একটি ইভেন্টকেও আবদ্ধ করে element। মজার বিষয় হ'ল এটি দ্বিতীয় আর্গুমেন্ট হিসাবে কোনও ফাংশনের পরিবর্তে নতুন বস্তুকে পাস করে। তবে এটি একা কাজ করবে না।

eventListenerইন্টারফেস বাস্তবায়ন করা হচ্ছে

এই কাজটি করার জন্য, আপনার অবজেক্টটির eventListenerইন্টারফেসটি প্রয়োগ করা দরকার । এটি সম্পাদন করার জন্য যা প্রয়োজন তা হ'ল বস্তুকে একটি handleEvent()পদ্ধতি দেওয়া method

এখানেই উত্তরাধিকার আসে।

MyCtor.prototype.handleEvent = function(event) {
    switch (event.type) {
        case "change": this.change(this.element.value);
    }
};

MyCtor.prototype.change = function(value) {
    this.data = value;
    this.element.value = value;
};

এটি অনেকগুলি বিভিন্ন উপায়ে রয়েছে যাতে এটি কাঠামোগত হতে পারে, তবে আপডেটগুলি সমন্বয় করার আপনার উদাহরণের জন্য, আমি সিদ্ধান্ত নিয়েছি যে change()পদ্ধতিটি কেবলমাত্র একটি মান গ্রহণ করবে, এবং handleEventইভেন্ট অবজেক্টের পরিবর্তে সেই মানটিই পাস করবে। এইভাবে change()কোনও ইভেন্ট ছাড়াও আহ্বান করা যেতে পারে।

সুতরাং এখন, যখন changeইভেন্টটি ঘটে, এটি উপাদান এবং .dataসম্পত্তি উভয়ই আপডেট করবে । আপনি যখন .change()জাভাস্ক্রিপ্ট প্রোগ্রামটিতে কল করবেন তখন একই ঘটনা ঘটবে ।

কোড ব্যবহার করে

এখন আপনি কেবলমাত্র নতুন অবজেক্টটি তৈরি করতে চান এবং এটি আপডেটগুলি করতে দিন। জেএস কোডে আপডেটগুলি ইনপুটটিতে উপস্থিত হবে এবং ইনপুটটির পরিবর্তনগুলি জেএস কোডে দৃশ্যমান হবে।

var obj = new MyCtor(document.getElementById("foo"), "20");

// simulate some JS based changes.
var i = 0;
setInterval(function() {
    obj.change(parseInt(obj.element.value) + ++i);
}, 3000);

ডেমো: http://jsfiddle.net/RkTMD/


5
+1 খুব পরিষ্কার পন্থা, খুব সহজভাবে বলা যায় এবং লোকেরা শেখার পক্ষে যথেষ্ট সহজ, আমার যা ছিল তা থেকে অনেক বেশি পরিষ্কার। একটি সাধারণ ব্যবহারের ক্ষেত্রে বস্তুর দৃষ্টিভঙ্গি উপস্থাপনের জন্য কোডগুলিতে টেম্পলেট ব্যবহার করা হয়। আমি ভাবছিলাম যে এটি এখানে কীভাবে কাজ করবে? গোঁফের মতো ইঞ্জিনগুলিতে আমি কিছু করি Mustache.render(template,object), ধরে নিই যে আমি কোনও বস্তুকে টেমপ্লেটের সাথে সিঙ্ক করতে চাই (গোঁফের সাথে সুনির্দিষ্ট নয়), আমি কীভাবে এটি করব?
বেনিয়ামিন গ্রুইনবাউম

3
@ বেনজামিন গ্রুয়েনবাউম: আমি ক্লায়েন্ট-সাইড টেম্পলেট ব্যবহার করি নি, তবে আমি কল্পনা করব যে গোঁফের সন্নিবেশ পয়েন্টগুলি সনাক্ত করার জন্য কিছু বাক্য গঠন রয়েছে এবং সিনট্যাক্সটিতে একটি লেবেল অন্তর্ভুক্ত রয়েছে। সুতরাং আমি ভাবব যে টেমপ্লেটের "স্থিতিশীল" অংশগুলি একটি অ্যারেতে সংরক্ষিত এইচটিএমএলের খণ্ডগুলিতে রেন্ডার হবে এবং গতিশীল অংশগুলি সেই খণ্ডগুলির মধ্যে চলে যাবে। তারপরে সন্নিবেশ পয়েন্টগুলিতে থাকা লেবেলগুলি বস্তুর বৈশিষ্ট্য হিসাবে ব্যবহৃত হবে। তারপরে যদি কেউ inputthose পয়েন্টগুলির মধ্যে একটি আপডেট করতে হয় তবে ইনপুট থেকে সেই বিন্দুতে ম্যাপিং হবে। আমি দ্রুত উদাহরণ দিয়ে আসতে পারি কিনা তা আমি দেখতে পাব।

1
@ বেনজামিন গ্রুয়েনবাউম: হুম ... আমি কীভাবে দুটি পৃথক উপাদানকে পরিষ্কারভাবে সমন্বয় করতে হবে তা নিয়ে ভাবিনি। আমি প্রথমে যা ভাবি তার থেকে এটি আরও কিছুটা জড়িত। যদিও আমি কৌতূহলী, তাই আমার এই বিষয়ে আরও পরে কাজ করা প্রয়োজন। :)

2
আপনি দেখতে পাবেন যে একটি প্রাথমিক Templateনির্মাতা রয়েছে যা পার্সিং করে, বিভিন্ন MyCtorবস্তু ধারণ করে এবং এর সনাক্তকারী দ্বারা প্রতিটি আপডেট করার জন্য একটি ইন্টারফেস সরবরাহ করে। যদি আপনার কোন প্রশ্ন থাকে তাহলে আমার জানতে দিন। :) সম্পাদনা করুন: ... পরিবর্তে এই লিঙ্কটি ব্যবহার করুন ... আমি ভুলে গিয়েছিলাম যে জেএস আপডেটগুলি প্রদর্শনের জন্য প্রতি 10 সেকেন্ডে আমার ইনপুট মানটিতে তাত্পর্যপূর্ণ বৃদ্ধি পেয়েছিল। এটি এটি সীমাবদ্ধ।


36

সুতরাং, আমি নিজের সমাধানটি পাত্রের মধ্যে ফেলে দেওয়ার সিদ্ধান্ত নিয়েছি। এখানে একটি কার্যকরী ফিজল । নোট করুন এটি কেবল খুব আধুনিক ব্রাউজারগুলিতে চলে।

এটি কি ব্যবহার করে

এই বাস্তবায়নটি অত্যন্ত আধুনিক - এর জন্য একটি (খুব) আধুনিক ব্রাউজার এবং ব্যবহারকারীদের দুটি নতুন প্রযুক্তি প্রয়োজন:

  • MutationObserverগুলি DOM মধ্যে পরিবর্তনগুলি (ঘটনা শ্রোতাকে পাশাপাশি ব্যবহার করা হয়) সনাক্ত করতে
  • Object.observeঅবজেক্টের পরিবর্তনগুলি সনাক্ত করতে এবং ডোমকে অবহিত করতে। বিপদ, যেহেতু এই উত্তরটি ওও লিখিত হয়েছে ECMAScript টিসি দ্বারা আলোচনা করা হয়েছে এবং তার বিরুদ্ধে সিদ্ধান্ত নেওয়া হয়েছে, তাই পলিফিল বিবেচনা করুন

কিভাবে এটা কাজ করে

  • উপাদানটিতে, একটি domAttribute:objAttributeম্যাপিং রাখুন - উদাহরণস্বরূপbind='textContent:name'
  • এটি ডেটাবাইন্ড ফাংশনে পড়ুন। উপাদান এবং বস্তু উভয়ই পর্যবেক্ষণ করুন।
  • যখন কোনও পরিবর্তন ঘটে - প্রাসঙ্গিক উপাদানটি আপডেট করুন।

সমাধান

এখানে dataBindফাংশনটি উল্লেখ করুন, এটি কোডের কেবল 20 লাইন এবং সংক্ষিপ্ত হতে পারে:

function dataBind(domElement, obj) {    
    var bind = domElement.getAttribute("bind").split(":");
    var domAttr = bind[0].trim(); // the attribute on the DOM element
    var itemAttr = bind[1].trim(); // the attribute the object

    // when the object changes - update the DOM
    Object.observe(obj, function (change) {
        domElement[domAttr] = obj[itemAttr]; 
    });
    // when the dom changes - update the object
    new MutationObserver(updateObj).observe(domElement, { 
        attributes: true,
        childList: true,
        characterData: true
    });
    domElement.addEventListener("keyup", updateObj);
    domElement.addEventListener("click",updateObj);
    function updateObj(){
        obj[itemAttr] = domElement[domAttr];   
    }
    // start the cycle by taking the attribute from the object and updating it.
    domElement[domAttr] = obj[itemAttr]; 
}

এখানে কিছু ব্যবহার রয়েছে:

এইচটিএমএল:

<div id='projection' bind='textContent:name'></div>
<input type='text' id='textView' bind='value:name' />

javascript:

var obj = {
    name: "Benjamin"
};
var el = document.getElementById("textView");
dataBind(el, obj);
var field = document.getElementById("projection");
dataBind(field,obj);

এখানে একটি কার্যকরী ফিজল । নোট করুন যে এই সমাধানটি বেশ জেনেরিক। অবজেক্ট.ওবিজার এবং মিউটেশন পর্যবেক্ষক শিমিং উপলব্ধ।


1
নিজেকে কোপ আউট - আমি শুধু মজা করার জন্য এই (es5) লিখতে কেউ যদি খুঁজে বের করে এটা দরকারী ঘটেছে jsfiddle.net/P9rMm
বেঞ্জামিন Gruenbaum

1
মনে রাখবেন যে যখন obj.nameকোনও সেটটার রয়েছে তখন এটি বাহ্যিকভাবে পর্যবেক্ষণ করা যায় না, তবে এটি সম্প্রচারিত করতে হবে যে এটি সেটারের মধ্যে থেকে পরিবর্তিত হয়েছে - html5rocks.com/en/tutorials/es7/observe/#toc-notifications - কিন্ডা কাজগুলিতে একটি রেঞ্চ ফেলে দেয় ওও () এর জন্য যদি আপনি সেটটার ব্যবহার করে আরও জটিল, পরস্পর নির্ভরশীল আচরণ চান। তদ্ব্যতীত, যখন obj.nameকনফিগারযোগ্য নয় , তখন সেটারটিকে পুনরায় সংজ্ঞায়িত করতে (নোটিফিকেশন যুক্ত করার জন্য বিভিন্ন কৌশল সহ) এছাড়াও অনুমোদিত নয় - সুতরাং ওও () এর সাথে জেনেরিকগুলি সেই নির্দিষ্ট ক্ষেত্রে পুরোপুরি বাদ দেওয়া হবে।
নোলো

8
অবজেক্ট.ওবিজার সমস্ত ব্রাউজার থেকে সরানো হয়েছে: caniuse.com/#feat=object-observe
JvdBerg

1
একটি প্রক্সি অবজেক্ট.ওবিজার, বা github.com/anywhichway/proxy-observe বা gist.github.com/ebidel/1b553d571f924da2da06 বা পুরানো পলিফিলের পরিবর্তে, গিথুব @ জেভিডিবার্গ
জিম্মন্ট

29

আমি আমার প্রিপোস্টারকে যুক্ত করতে চাই। আমি কিছুটা ভিন্ন পদ্ধতির পরামর্শ দিচ্ছি যা আপনাকে কোনও পদ্ধতি ব্যবহার না করেই কেবল আপনার অবজেক্টের জন্য একটি নতুন মান নির্ধারণ করতে দেয়। এটি অবশ্যই লক্ষণীয় যে এটি বিশেষত পুরানো ব্রাউজারগুলির দ্বারা সমর্থিত নয় এবং IE9 এর জন্য এখনও একটি পৃথক ইন্টারফেসের প্রয়োজন।

সবচেয়ে লক্ষণীয় বিষয় হল আমার পদ্ধতির ঘটনাগুলি ব্যবহার করে না।

গেটারস এবং সিটারস

আমার প্রস্তাবটি গ্রাহক এবং সেটটারগুলির তুলনামূলকভাবে তরুণ বৈশিষ্ট্যটি বিশেষত কেবল সেটটারগুলি ব্যবহার করে। সাধারণভাবে বলতে গেলে, মিউটররা আমাদের নির্দিষ্ট বৈশিষ্ট্যগুলি কীভাবে একটি মূল্য নির্ধারণ এবং পুনরুদ্ধার করা হয় তার আচরণকে "কাস্টমাইজ" করার অনুমতি দেয়।

একটি বাস্তবায়ন যা আমি এখানে ব্যবহার করব তা হ'ল Object.defineProperty পদ্ধতি। এটি ফায়ারফক্স, গুগল ক্রোম এবং - আমি মনে করি - আই 9 তে কাজ করে। অন্যান্য ব্রাউজারগুলি পরীক্ষা করা যায় নি, তবে এটি কেবল তত্ত্ব হিসাবে ...

যাইহোক, এটি তিনটি পরামিতি গ্রহণ করে। প্রথম প্যারামিটারটি এমন একটি বস্তু যা আপনি কোনও নতুন সম্পত্তি সংজ্ঞায়িত করতে চান, দ্বিতীয়টি নতুন সম্পত্তির নামের সাথে সাদৃশ্যযুক্ত একটি স্ট্রিং এবং সর্বশেষে একটি "বর্ণনাকারী অবজেক্ট" নতুন সম্পত্তির আচরণ সম্পর্কিত তথ্য সরবরাহ করে।

দুটি বিশেষত আকর্ষণীয় বর্ণনাকারী হলেন getএবং set। একটি উদাহরণ নীচের মত কিছু দেখতে হবে। নোট করুন যে এই দুটি ব্যবহার করা অন্যান্য 4 বর্ণনাকারীর ব্যবহার নিষিদ্ধ করে।

function MyCtor( bindTo ) {
    // I'll omit parameter validation here.

    Object.defineProperty(this, 'value', {
        enumerable: true,
        get : function ( ) {
            return bindTo.value;
        },
        set : function ( val ) {
            bindTo.value = val;
        }
    });
}

এখন এটির ব্যবহারটি কিছুটা আলাদা হয়ে যায়:

var obj = new MyCtor(document.getElementById('foo')),
    i = 0;
setInterval(function() {
    obj.value += ++i;
}, 3000);

আমি জোর দিয়ে বলতে চাই যে এটি কেবল আধুনিক ব্রাউজারগুলির জন্যই কাজ করে।

ওয়ার্ডিং ফিডল: http://jsfiddle.net/Derija93/RkTMD/1/


2
যদি কেবল আমাদের কাছে হারমোনি Proxyঅবজেক্ট থাকে :) সেটারগুলি একটি দুর্দান্ত ধারণা বলে মনে হয়, তবে কি আমাদের আসল অবজেক্টগুলিকে সংশোধন করার প্রয়োজন হবে না? এছাড়াও, পাশের নোটে - Object.createএখানে ব্যবহার করা যেতে পারে (আবারও ধরে নেওয়া, আধুনিক ব্রাউজারটি যা দ্বিতীয় প্যারামিটারের জন্য মঞ্জুরিপ্রাপ্ত)। এছাড়াও, সেটার / গেটরটি 'প্রোজেক্ট' করতে অবজেক্টের এবং ডিওএম উপাদানটির একটি আলাদা মান ব্যবহৃত হতে পারে :)। আমি ভাবছি যদি আপনারও টেম্প্লেটিংয়ের বিষয়ে কোনও অন্তর্দৃষ্টি রয়েছে, এটি এখানে একটি বাস্তব চ্যালেঞ্জ বলে মনে হচ্ছে, বিশেষ করে সুন্দরভাবে কাঠামো করার জন্য :)
বেনজামিন গ্রুইনবাউম

আমার প্রিপোস্টারের মতো, আমিও ক্লায়েন্ট-সাইড টেম্প্লেটিং ইঞ্জিনগুলির সাথে খুব বেশি কাজ করি না, দুঃখিত। :( তবে আসল বস্তুগুলিকে সংশোধন করে আপনি কী বোঝাতে চেয়েছেন ? এবং আপনি কীভাবে সেটার / গেটর ব্যবহার করতে পারবেন তা আপনি কীভাবে বুঝতে পেরেছিলেন সে সম্পর্কে আপনার চিন্তাভাবনাগুলি বুঝতে চাই ... ... এখানে প্রাপ্তি / সেটটারগুলি কোনও কিছুর জন্য ব্যবহৃত হয় না তবে সমস্ত ইনপুট পুনঃনির্দেশ করা এবং অবজেক্টটি থেকে ডিওএম উপাদানটিতে পুনরুদ্ধার করা Proxy, যেমনটি আপনি বলেছেন ঠিক তেমন একটি ;;) দুটি স্বতন্ত্র বৈশিষ্ট্য সিঙ্ক্রোনাইজ করার জন্য আমি চ্যালেঞ্জটি বুঝতে পেরেছিলাম। আমার পদ্ধতি উভয়ের একটি অপসারণ করে।
কিরুস

Proxyগেটরস / সেটটারগুলি ব্যবহারের প্রয়োজনীয়তাটি দূর করবে, উপাদানগুলির কী বৈশিষ্ট্য রয়েছে তা না জেনে আপনি উপাদানগুলিকে আবদ্ধ করতে পারেন। আমি যা বোঝাতে চেয়েছি তা হ'ল গ্রাহকরা বিন্দু.ওলুয়ের চেয়ে বেশি পরিবর্তন করতে পারে তারা যুক্তি (এবং এমনকি কোনও টেম্পলেট এমনকি) ধারণ করতে পারে। প্রশ্নটি কীভাবে এই টেমপ্লেটটিকে সামনে রেখে দ্বি-নির্দেশমূলক বাঁধাই বজায় রাখা যায়? যাক আমি আমার অবজেক্টটিকে একটি ফর্মের সাথে ম্যাপ করছি, আমি উপাদানটি এবং ফর্ম দুটি সিঙ্ক করে বজায় রাখতে চাই এবং আমি ভাবছি যে আমি কীভাবে এই ধরণের জিনিসটি নিয়ে যাব। কীভাবে নকআউট শিখতে পারে তা আপনি পরীক্ষা করে দেখতে পারেন .knockoutjs.com/#/?tutorial=intro উদাহরণস্বরূপ
বেনিয়ামিন

নিবন্ধন করুন আমি এটি একটি চেহারা দিতে হবে।
কিউরুস

@ বেনজামিন গ্রুয়েনবাউম আমি বুঝতে পারি আপনি কী বোঝার চেষ্টা করছেন। টেমপ্লেটগুলি মাথায় রেখে এই সমস্ত সেট আপ করা আরও কিছুটা কঠিন হতে পারে। আমি এই স্ক্রিপ্টটিতে কিছু সময়ের জন্য কাজ করব (এবং এটির ধারাবাহিকভাবে রিবাজ করব)। তবে আপাতত আমি একটু বিরতি নিচ্ছি। আমি আসলে এই জন্য যথেষ্ট সময় নেই।
কিরুস

7

আমি মনে করি আমার উত্তরটি আরও প্রযুক্তিগত হবে, তবে অন্যরা যেমন বিভিন্ন কৌশল ব্যবহার করে একই জিনিস উপস্থাপন করে তেমন আলাদা নয়।
সুতরাং, প্রথমে প্রথমে, এই সমস্যার সমাধান হ'ল "পর্যবেক্ষক" হিসাবে পরিচিত একটি ডিজাইনের প্যাটার্ন ব্যবহার করা, এটি আপনাকে আপনার উপস্থাপনা থেকে আপনার ডেটা ডিকুয়াল করে দেয়, যার ফলে একটি শব্দের পরিবর্তনগুলি তাদের শ্রোতাদের কাছে সম্প্রচারিত করা যায় তবে এই ক্ষেত্রে এটি দ্বিমুখী করা হয়েছে

ডোম থেকে জেএস পথের জন্য

ডিওএম থেকে জেএস অবজেক্টে ডেটা বাঁধতে আপনি dataবৈশিষ্ট্যের আকারে (বা ক্লাসগুলির যদি আপনার সামঞ্জস্যের প্রয়োজন হয়) আকারে মার্কআপ যুক্ত করতে পারেন :

<input type="text" data-object="a" data-property="b" id="b" class="bind" value=""/>
<input type="text" data-object="a" data-property="c" id="c" class="bind" value=""/>
<input type="text" data-object="d" data-property="e" id="e" class="bind" value=""/>

এই উপায়টি ব্যবহার করে querySelectorAll(বা getElementsByClassNameসামঞ্জস্যের জন্য পুরানো বন্ধু ) জেএসের মাধ্যমে অ্যাক্সেস করা যায় ।

এখন আপনি ইভেন্টগুলিকে বিভিন্নভাবে পরিবর্তনগুলি শোনার সাথে বেঁধে রাখতে পারেন: প্রতি বস্তুর জন্য একজন শ্রোতা বা ধারক / নথির জন্য একটি বড় শ্রোতা। দস্তাবেজ / ধারককে বাঁধাই ইভেন্টটি বা এটির শিশুদের প্রতিটি পরিবর্তনের জন্য ইভেন্টকে ট্রিগার করবে, এটি একটি ছোট মেমরির পদচিহ্ন ছড়িয়ে দেবে তবে ইভেন্ট কলগুলি স্প্যান করবে।
কোডটি এরকম কিছু দেখবে:

//Bind to each element
var elements = document.querySelectorAll('input[data-property]');

function toJS(){
    //Assuming `a` is in scope of the document
    var obj = document[this.data.object];
    obj[this.data.property] = this.value;
}

elements.forEach(function(el){
    el.addEventListener('change', toJS, false);
}

//Bind to document
function toJS2(){
    if (this.data && this.data.object) {
        //Again, assuming `a` is in document's scope
        var obj = document[this.data.object];
        obj[this.data.property] = this.value;
    }
}

document.addEventListener('change', toJS2, false);

জেএস do ডোম উপায় জন্য

আপনার দুটি জিনিস প্রয়োজন হবে: একটি মেটা-অবজেক্ট যা ডাইনি DOM উপাদানটির রেফারেন্সগুলিকে ধারণ করবে প্রতিটি জেএস অবজেক্ট / বৈশিষ্ট্য এবং বস্তুর পরিবর্তনগুলি শোনার উপায়ের সাথে আবদ্ধ। এটি মূলত একইভাবে: আপনাকে অবজেক্টের পরিবর্তনগুলি শুনতে হবে এবং তারপরে এটি ডিওএম নোডের সাথে আবদ্ধ করতে হবে, যেহেতু আপনার অবজেক্টটির "থাকতে পারে না" মেটাডেটা আপনার অন্য কোনও অবজেক্টের প্রয়োজন হবে যা মেটাডেটা একভাবে ধারণ করে holds মেটাডেটা অবজেক্টের বৈশিষ্ট্যগুলিতে সম্পত্তি নামের মানচিত্র। কোডটি এরকম কিছু হবে:

var a = {
        b: 'foo',
        c: 'bar'
    },
    d = {
        e: 'baz'
    },
    metadata = {
        b: 'b',
        c: 'c',
        e: 'e'
    };
function toDOM(changes){
    //changes is an array of objects changed and what happened
    //for now i'd recommend a polyfill as this syntax is still a proposal
    changes.forEach(function(change){
        var element = document.getElementById(metadata[change.name]);
        element.value = change.object[change.name];
    });
}
//Side note: you can also use currying to fix the second argument of the function (the toDOM method)
Object.observe(a, toDOM);
Object.observe(d, toDOM);

আমি আশা করি যে আমি সাহায্য করেছিলাম।


.observer ব্যবহার করে তুলনার সমস্যা নেই?
মোহসেন শাকিবা

আপাতত এটির জন্য একটি শিম বা পলফিলের প্রয়োজন কারণ এখনকার ক্রোমে সমর্থনটি Object.observeউপস্থাপিত। caniuse.com/#feat=object-observ
ম্যাডক্যাম্পোস

9
অবজেক্ট.ওবজার মারা গেছে। শুধু ভেবেছি আমি এখানে এখানে নোট করব।
বেনিয়ামিন গ্রুইনবাউম

@ বেঞ্জামিন গ্রুয়েনবাউম এখন মারা যাওয়ার পরে যে জিনিসটি ব্যবহার করবেন তা সঠিক কী?
জননী

1
@ জোহ্নি যদি আমি ভুল না করি তবে এটি প্রক্সি ট্র্যাপ হবে কারণ তারা কোনও বস্তুর সাথে আমি কী করতে পারি তার আরও দানাদার নিয়ন্ত্রণের অনুমতি দেয় তবে আমাকে এটি তদন্ত করতে হবে।
ম্যাডক্যাম্পোস

7

গতকাল, আমি ডেটা বাঁধতে আমার নিজের মতো করে লিখতে শুরু করেছি।

এটি খেলতে খুব মজার।

আমি মনে করি এটি সুন্দর এবং খুব দরকারী। কমপক্ষে ফায়ারফক্স এবং ক্রোম ব্যবহার করে আমার পরীক্ষাগুলিতে এজ অবশ্যই খুব বেশি কাজ করবে। অন্যদের সম্পর্কে নিশ্চিত নয়, তবে তারা যদি প্রক্সি সমর্থন করে তবে আমি মনে করি এটি কার্যকর হবে।

https://jsfiddle.net/2ozoovne/1/

<H1>Bind Context 1</H1>
<input id='a' data-bind='data.test' placeholder='Button Text' />
<input id='b' data-bind='data.test' placeholder='Button Text' />
<input type=button id='c' data-bind='data.test' />
<H1>Bind Context 2</H1>
<input id='d' data-bind='data.otherTest' placeholder='input bind' />
<input id='e' data-bind='data.otherTest' placeholder='input bind' />
<input id='f' data-bind='data.test' placeholder='button 2 text - same var name, other context' />
<input type=button id='g' data-bind='data.test' value='click here!' />
<H1>No bind data</H1>
<input id='h' placeholder='not bound' />
<input id='i' placeholder='not bound'/>
<input type=button id='j' />

কোডটি এখানে:

(function(){
    if ( ! ( 'SmartBind' in window ) ) { // never run more than once
        // This hack sets a "proxy" property for HTMLInputElement.value set property
        var nativeHTMLInputElementValue = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
        var newDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
        newDescriptor.set=function( value ){
            if ( 'settingDomBind' in this )
                return;
            var hasDataBind=this.hasAttribute('data-bind');
            if ( hasDataBind ) {
                this.settingDomBind=true;
                var dataBind=this.getAttribute('data-bind');
                if ( ! this.hasAttribute('data-bind-context-id') ) {
                    console.error("Impossible to recover data-bind-context-id attribute", this, dataBind );
                } else {
                    var bindContextId=this.getAttribute('data-bind-context-id');
                    if ( bindContextId in SmartBind.contexts ) {
                        var bindContext=SmartBind.contexts[bindContextId];
                        var dataTarget=SmartBind.getDataTarget(bindContext, dataBind);
                        SmartBind.setDataValue( dataTarget, value);
                    } else {
                        console.error( "Invalid data-bind-context-id attribute", this, dataBind, bindContextId );
                    }
                }
                delete this.settingDomBind;
            }
            nativeHTMLInputElementValue.set.bind(this)( value );
        }
        Object.defineProperty(HTMLInputElement.prototype, 'value', newDescriptor);

    var uid= function(){
           return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
               var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
               return v.toString(16);
          });
   }

        // SmartBind Functions
        window.SmartBind={};
        SmartBind.BindContext=function(){
            var _data={};
            var ctx = {
                "id" : uid()    /* Data Bind Context Id */
                , "_data": _data        /* Real data object */
                , "mapDom": {}          /* DOM Mapped objects */
                , "mapDataTarget": {}       /* Data Mapped objects */
            }
            SmartBind.contexts[ctx.id]=ctx;
            ctx.data=new Proxy( _data, SmartBind.getProxyHandler(ctx, "data"))  /* Proxy object to _data */
            return ctx;
        }

        SmartBind.getDataTarget=function(bindContext, bindPath){
            var bindedObject=
                { bindContext: bindContext
                , bindPath: bindPath 
                };
            var dataObj=bindContext;
            var dataObjLevels=bindPath.split('.');
            for( var i=0; i<dataObjLevels.length; i++ ) {
                if ( i == dataObjLevels.length-1 ) { // last level, set value
                    bindedObject={ target: dataObj
                    , item: dataObjLevels[i]
                    }
                } else {    // digg in
                    if ( ! ( dataObjLevels[i] in dataObj ) ) {
                        console.warn("Impossible to get data target object to map bind.", bindPath, bindContext);
                        break;
                    }
                    dataObj=dataObj[dataObjLevels[i]];
                }
            }
            return bindedObject ;
        }

        SmartBind.contexts={};
        SmartBind.add=function(bindContext, domObj){
            if ( typeof domObj == "undefined" ){
                console.error("No DOM Object argument given ", bindContext);
                return;
            }
            if ( ! domObj.hasAttribute('data-bind') ) {
                console.warn("Object has no data-bind attribute", domObj);
                return;
            }
            domObj.setAttribute("data-bind-context-id", bindContext.id);
            var bindPath=domObj.getAttribute('data-bind');
            if ( bindPath in bindContext.mapDom ) {
                bindContext.mapDom[bindPath][bindContext.mapDom[bindPath].length]=domObj;
            } else {
                bindContext.mapDom[bindPath]=[domObj];
            }
            var bindTarget=SmartBind.getDataTarget(bindContext, bindPath);
            bindContext.mapDataTarget[bindPath]=bindTarget;
            domObj.addEventListener('input', function(){ SmartBind.setDataValue(bindTarget,this.value); } );
            domObj.addEventListener('change', function(){ SmartBind.setDataValue(bindTarget, this.value); } );
        }

        SmartBind.setDataValue=function(bindTarget,value){
            if ( ! ( 'target' in bindTarget ) ) {
                var lBindTarget=SmartBind.getDataTarget(bindTarget.bindContext, bindTarget.bindPath);
                if ( 'target' in lBindTarget ) {
                    bindTarget.target=lBindTarget.target;
                    bindTarget.item=lBindTarget.item;
                } else {
                    console.warn("Still can't recover the object to bind", bindTarget.bindPath );
                }
            }
            if ( ( 'target' in bindTarget ) ) {
                bindTarget.target[bindTarget.item]=value;
            }
        }
        SmartBind.getDataValue=function(bindTarget){
            if ( ! ( 'target' in bindTarget ) ) {
                var lBindTarget=SmartBind.getDataTarget(bindTarget.bindContext, bindTarget.bindPath);
                if ( 'target' in lBindTarget ) {
                    bindTarget.target=lBindTarget.target;
                    bindTarget.item=lBindTarget.item;
                } else {
                    console.warn("Still can't recover the object to bind", bindTarget.bindPath );
                }
            }
            if ( ( 'target' in bindTarget ) ) {
                return bindTarget.target[bindTarget.item];
            }
        }
        SmartBind.getProxyHandler=function(bindContext, bindPath){
            return  {
                get: function(target, name){
                    if ( name == '__isProxy' )
                        return true;
                    // just get the value
                    // console.debug("proxy get", bindPath, name, target[name]);
                    return target[name];
                }
                ,
                set: function(target, name, value){
                    target[name]=value;
                    bindContext.mapDataTarget[bindPath+"."+name]=value;
                    SmartBind.processBindToDom(bindContext, bindPath+"."+name);
                    // console.debug("proxy set", bindPath, name, target[name], value );
                    // and set all related objects with this target.name
                    if ( value instanceof Object) {
                        if ( !( name in target) || ! ( target[name].__isProxy ) ){
                            target[name]=new Proxy(value, SmartBind.getProxyHandler(bindContext, bindPath+'.'+name));
                        }
                        // run all tree to set proxies when necessary
                        var objKeys=Object.keys(value);
                        // console.debug("...objkeys",objKeys);
                        for ( var i=0; i<objKeys.length; i++ ) {
                            bindContext.mapDataTarget[bindPath+"."+name+"."+objKeys[i]]=target[name][objKeys[i]];
                            if ( typeof value[objKeys[i]] == 'undefined' || value[objKeys[i]] == null || ! ( value[objKeys[i]] instanceof Object ) || value[objKeys[i]].__isProxy )
                                continue;
                            target[name][objKeys[i]]=new Proxy( value[objKeys[i]], SmartBind.getProxyHandler(bindContext, bindPath+'.'+name+"."+objKeys[i]));
                        }
                        // TODO it can be faster than run all items
                        var bindKeys=Object.keys(bindContext.mapDom);
                        for ( var i=0; i<bindKeys.length; i++ ) {
                            // console.log("test...", bindKeys[i], " for ", bindPath+"."+name);
                            if ( bindKeys[i].startsWith(bindPath+"."+name) ) {
                                // console.log("its ok, lets update dom...", bindKeys[i]);
                                SmartBind.processBindToDom( bindContext, bindKeys[i] );
                            }
                        }
                    }
                    return true;
                }
            };
        }
        SmartBind.processBindToDom=function(bindContext, bindPath) {
            var domList=bindContext.mapDom[bindPath];
            if ( typeof domList != 'undefined' ) {
                try {
                    for ( var i=0; i < domList.length ; i++){
                        var dataTarget=SmartBind.getDataTarget(bindContext, bindPath);
                        if ( 'target' in dataTarget )
                            domList[i].value=dataTarget.target[dataTarget.item];
                        else
                            console.warn("Could not get data target", bindContext, bindPath);
                    }
                } catch (e){
                    console.warn("bind fail", bindPath, bindContext, e);
                }
            }
        }
    }
})();

তারপরে, সেট করতে, ঠিক:

var bindContext=SmartBind.BindContext();
SmartBind.add(bindContext, document.getElementById('a'));
SmartBind.add(bindContext, document.getElementById('b'));
SmartBind.add(bindContext, document.getElementById('c'));

var bindContext2=SmartBind.BindContext();
SmartBind.add(bindContext2, document.getElementById('d'));
SmartBind.add(bindContext2, document.getElementById('e'));
SmartBind.add(bindContext2, document.getElementById('f'));
SmartBind.add(bindContext2, document.getElementById('g'));

setTimeout( function() {
    document.getElementById('b').value='Via Script works too!'
}, 2000);

document.getElementById('g').addEventListener('click',function(){
bindContext2.data.test='Set by js value'
})

আপাতত, আমি স্রেফ এইচটিএমএলপুট উপাদান সংজ্ঞা যুক্ত করেছি।

আপনি কীভাবে এটি উন্নতি করতে জানেন তা আমাকে জানাবেন।


6

"জাভাস্ক্রিপ্টে সহজ দ্বি- উপাত্তে ডেটা বাইন্ডিং " এই লিঙ্কটিতে 2-উপায় ডেটা-বাঁধাইয়ের একটি খুব সাধারণ নগ্নপুঞ্জ বাস্তবায়ন রয়েছে

নকআউটজ, ব্যাকবোন.জেএস এবং অ্যাগ্রিলিটি.জেএস এর ধারণাগুলির সাথে পূর্ববর্তী লিঙ্কটি এই হালকা ওজন এবং দ্রুত এমভিভিএম কাঠামো, মডেলভিউ.জেএসকে নেতৃত্ব দিয়েছে jQuery উপর ভিত্তি করে যা jQuery এর সাথে দুর্দান্ত অভিনয় করে এবং যার মধ্যে আমি নম্র (বা সম্ভবত এত নম্র নয়) লেখক।

নীচে নমুনা কোড পুনরুত্পাদন করা ( ব্লগ পোস্ট লিঙ্ক থেকে ):

ডেটাবাইন্ডারের জন্য নমুনা কোড

function DataBinder( object_id ) {
  // Use a jQuery object as simple PubSub
  var pubSub = jQuery({});

  // We expect a `data` element specifying the binding
  // in the form: data-bind-<object_id>="<property_name>"
  var data_attr = "bind-" + object_id,
      message = object_id + ":change";

  // Listen to change events on elements with the data-binding attribute and proxy
  // them to the PubSub, so that the change is "broadcasted" to all connected objects
  jQuery( document ).on( "change", "[data-" + data_attr + "]", function( evt ) {
    var $input = jQuery( this );

    pubSub.trigger( message, [ $input.data( data_attr ), $input.val() ] );
  });

  // PubSub propagates changes to all bound elements, setting value of
  // input tags or HTML content of other tags
  pubSub.on( message, function( evt, prop_name, new_val ) {
    jQuery( "[data-" + data_attr + "=" + prop_name + "]" ).each( function() {
      var $bound = jQuery( this );

      if ( $bound.is("input, textarea, select") ) {
        $bound.val( new_val );
      } else {
        $bound.html( new_val );
      }
    });
  });

  return pubSub;
}

জাভাস্ক্রিপ্ট অবজেক্টের উদ্বেগের জন্য, এই পরীক্ষার খাতিরে কোনও ব্যবহারকারী মডেলের নূন্যতম বাস্তবায়ন নিম্নলিখিত হতে পারে:

function User( uid ) {
  var binder = new DataBinder( uid ),

      user = {
        attributes: {},

        // The attribute setter publish changes using the DataBinder PubSub
        set: function( attr_name, val ) {
          this.attributes[ attr_name ] = val;
          binder.trigger( uid + ":change", [ attr_name, val, this ] );
        },

        get: function( attr_name ) {
          return this.attributes[ attr_name ];
        },

        _binder: binder
      };

  // Subscribe to the PubSub
  binder.on( uid + ":change", function( evt, attr_name, new_val, initiator ) {
    if ( initiator !== user ) {
      user.set( attr_name, new_val );
    }
  });

  return user;
}

এখন, যখনই আমরা কোনও মডেলটির সম্পত্তিটি ইউআইয়ের একটি অংশে আবদ্ধ করতে চাই আমাদের কেবলমাত্র এইচটিএমএল উপাদানটির জন্য একটি উপযুক্ত ডেটা অ্যাট্রিবিউট সেট করতে হবে:

// javascript
var user = new User( 123 );
user.set( "name", "Wolfgang" );

<!-- html -->
<input type="number" data-bind-123="name" />

যদিও এই লিঙ্কটি প্রশ্নের উত্তর দিতে পারে, উত্তরের প্রয়োজনীয় অংশগুলি এখানে অন্তর্ভুক্ত করা এবং রেফারেন্সের জন্য লিঙ্কটি সরবরাহ করা ভাল। লিঙ্কযুক্ত পৃষ্ঠাগুলি পরিবর্তিত হলে লিঙ্ক-শুধুমাত্র উত্তরগুলি অবৈধ হতে পারে।
স্যাম হ্যানলি

@ স্প্যানলে উল্লেখ করা হয়েছে, আমার আরও সময় পেলে সম্ভবত আপডেট করব, কারণ উত্তর পোস্টের জন্য এটি দীর্ঘতর কোড
নিকস এম।

@ স্প্যানলি, রেফারেন্সড লিংক থেকে উত্তরে নমুনা কোড পুনরুত্পাদন করা (যদিও আমি মনে করি এটি বেশিরভাগ সময়ই ডুপ্লিকেট সামগ্রী তৈরি করে)
নিকস এম।

1
এটি অবশ্যই সদৃশ সামগ্রী তৈরি করে, তবে এটি হ'ল ব্লগ লিঙ্কগুলি প্রায়শই সময়ের সাথে ভেঙে যেতে পারে এবং এখানে প্রাসঙ্গিক বিষয়বস্তু সদৃশ করে এটি নিশ্চিত করে যে এটি ভবিষ্যতে পাঠকদের জন্য উপলব্ধ এবং দরকারী হবে। উত্তর এখন দুর্দান্ত দেখাচ্ছে!
স্যাম হ্যানলি

3

কোনও উপাদানটির মান পরিবর্তন করা কোনও ডিওএম ইভেন্টকে ট্রিগার করতে পারে । শ্রোতারা যা ইভেন্টগুলিতে প্রতিক্রিয়া জানায় তা জাভাস্ক্রিপ্টে ডেটা বাঁধাই প্রয়োগ করতে ব্যবহার করা যেতে পারে।

উদাহরণ স্বরূপ:

function bindValues(id1, id2) {
  const e1 = document.getElementById(id1);
  const e2 = document.getElementById(id2);
  e1.addEventListener('input', function(event) {
    e2.value = event.target.value;
  });
  e2.addEventListener('input', function(event) {
    e1.value = event.target.value;
  });
}

এখানে কোড এবং একটি ডেমো যা দেখায় যে কীভাবে DOM উপাদানগুলি একে অপরের সাথে বা জাভাস্ক্রিপ্ট অবজেক্টের সাথে আবদ্ধ হতে পারে।


3

যে কোনও এইচটিএমএল ইনপুট বেঁধে রাখুন

<input id="element-to-bind" type="text">

দুটি ফাংশন সংজ্ঞায়িত করুন:

function bindValue(objectToBind) {
var elemToBind = document.getElementById(objectToBind.id)    
elemToBind.addEventListener("change", function() {
    objectToBind.value = this.value;
})
}

function proxify(id) { 
var handler = {
    set: function(target, key, value, receiver) {
        target[key] = value;
        document.getElementById(target.id).value = value;
        return Reflect.set(target, key, value);
    },
}
return new Proxy({id: id}, handler);
}

ফাংশন ব্যবহার করুন:

var myObject = proxify('element-to-bind')
bindValue(myObject);

3

এখানে একটি ধারণা ব্যবহার করে Object.defineProperty যা কোনও সম্পত্তির অ্যাক্সেসের পদ্ধতিটি সরাসরি পরিবর্তন করে।

কোড:

function bind(base, el, varname) {
    Object.defineProperty(base, varname, {
        get: () => {
            return el.value;
        },
        set: (value) => {
            el.value = value;
        }
    })
}

ব্যবহার:

var p = new some_class();
bind(p,document.getElementById("someID"),'variable');

p.variable="yes"

ভাজা: এখানে


2

আমাদের জেএস এবং জেএসগুলিকে দেখার জন্য বাধ্যতামূলক দৃষ্টিভঙ্গি তৈরি করার জন্য আমি অ্যানকিপ্রেস এবং অনভিচ ইভেন্ট হ্যান্ডলারগুলি ব্যবহার করে কিছু বেসিক জাভাস্ক্রিপ্ট উদাহরণ দিয়েছি

এখানে উদাহরণস্বরূপ http://plnkr.co/edit/7hSOIFRTvqLAvdZT4Bcc?p= পূর্বরূপ

<!DOCTYPE html>
<html>
<body>

    <p>Two way binding data.</p>

    <p>Binding data from  view to JS</p>

    <input type="text" onkeypress="myFunction()" id="myinput">
    <p id="myid"></p>
    <p>Binding data from  js to view</p>
    <input type="text" id="myid2" onkeypress="myFunction1()" oninput="myFunction1()">
    <p id="myid3" onkeypress="myFunction1()" id="myinput" oninput="myFunction1()"></p>

    <script>

        document.getElementById('myid2').value="myvalue from script";
        document.getElementById('myid3').innerHTML="myvalue from script";
        function myFunction() {
            document.getElementById('myid').innerHTML=document.getElementById('myinput').value;
        }
        document.getElementById("myinput").onchange=function(){

            myFunction();

        }
        document.getElementById("myinput").oninput=function(){

            myFunction();

        }

        function myFunction1() {

            document.getElementById('myid3').innerHTML=document.getElementById('myid2').value;
        }
    </script>

</body>
</html>

2
<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
</head>
<body>

<input type="text" id="demo" name="">
<p id="view"></p>
<script type="text/javascript">
    var id = document.getElementById('demo');
    var view = document.getElementById('view');
    id.addEventListener('input', function(evt){
        view.innerHTML = this.value;
    });

</script>
</body>
</html>

2

কোনও ইনপুট (দ্বিমুখী বাইন্ডিং) এ পরিবর্তনশীলকে বাঁধার সহজ উপায় হ'ল সরাসরি গিটার এবং সেটারের ইনপুট উপাদানটি সরাসরি অ্যাক্সেস করা:

var variable = function(element){                    
                   return {
                       get : function () { return element.value;},
                       set : function (value) { element.value = value;} 
                   }
               };

এইচটিএমএলে:

<input id="an-input" />
<input id="another-input" />

এবং ব্যবহার করতে:

var myVar = new variable(document.getElementById("an-input"));
myVar.set(10);

// and another example:
var myVar2 = new variable(document.getElementById("another-input"));
myVar.set(myVar2.get());


গেটর / সেটার ছাড়াই উপরের কাজগুলি করার একটি কল্পিত উপায়:

var variable = function(element){

                return function () {
                    if(arguments.length > 0)                        
                        element.value = arguments[0];                                           

                    else return element.value;                                                  
                }

        }

ব্যবহার করা:

var v1 = new variable(document.getElementById("an-input"));
v1(10); // sets value to 20.
console.log(v1()); // reads value.

1

ভ্যানিলা জাভাস্ক্রিপ্টে এটি খুব সাধারণ দ্বিমুখী ডেটা বাঁধাই ....

<input type="text" id="inp" onkeyup="document.getElementById('name').innerHTML=document.getElementById('inp').value;">

<div id="name">

</div>


2
অবশ্যই এটি কেবল অন্কিপ ইভেন্টের সাথে কাজ করবে? যেমন আপনি যদি একটি এজাক্স অনুরোধ করে থাকেন এবং জাভাস্ক্রিপ্টের মাধ্যমে অভ্যন্তরীণ এইচটিএমএল পরিবর্তন করেছেন তবে এটি কাজ করবে না
জ্যাচ স্মিথ

1

পার্টিতে দেরীতে, বিশেষত যেহেতু আমি 2 মাস আগে / বছর আগে লিব লিখেছি, আমি সেগুলি পরে উল্লেখ করব, তবে এখনও আমার কাছে প্রাসঙ্গিক বলে মনে হচ্ছে। এটিকে সত্যিই সংক্ষিপ্ত স্পয়লার হিসাবে তৈরি করতে, আমার পছন্দের প্রযুক্তিগুলি হ'ল:

  • Proxy মডেল পর্যবেক্ষণ জন্য
  • MutationObserver DOM এর ট্র্যাকিং পরিবর্তনের জন্য (বাধ্যতামূলক কারণে, মান পরিবর্তনের জন্য নয়)
  • মান পরিবর্তন (মডেল ফ্লো থেকে দেখুন) নিয়মিত addEventListenerহ্যান্ডলারের মাধ্যমে পরিচালিত হয়

আইএমএইচও, ওপি ছাড়াও, ডেটা বাঁধাইয়ের প্রয়োগটিও গুরুত্বপূর্ণ:

  • বিভিন্ন অ্যাপ লাইফাইসাইকেলের কেসগুলি হ্যান্ডেল করুন (এইচটিএমএল প্রথমে, তারপরে জেএস, জেএস প্রথম তারপরে এইচটিএমএল, গতিশীল বৈশিষ্ট্য পরিবর্তন ইত্যাদি)
  • মডেলটির গভীর বাঁধাইয়ের অনুমতি দিন, যাতে কেউ বাঁধতে পারে user.address.block
  • মডেল হিসেবে অ্যারে সঠিকভাবে সমর্থিত হতে হবে ( shift, spliceএবং একইভাবে)
  • শ্যাডোডোম হ্যান্ডেল করুন
  • প্রযুক্তির প্রতিস্থাপনের পক্ষে যতটা সম্ভব সহজ হওয়ার চেষ্টা করা, সুতরাং যে কোনও টেম্প্লেটিং উপ-ভাষাগুলি একটি অ-ভবিষ্যত-পরিবর্তন-বান্ধব পদ্ধতির কারণ এটি কাঠামোর সাথে ভারী ভারী হয়

এই সমস্ত বিবেচনায় নিয়ে যাওয়া, আমার মতে এটি কয়েক ডজন জেএস লাইন ফেলে দেওয়া অসম্ভব করে তোলে। আমি এটি lib পরিবর্তে একটি নিদর্শন হিসাবে করার চেষ্টা করেছি - আমার জন্য কাজ করে না।

এর পরে, Object.observeসরিয়ে ফেলা হয়েছে, এবং এখনও দেওয়া হয়েছে যে মডেল পর্যবেক্ষণ অত্যন্ত গুরুত্বপূর্ণ - এই পুরো অংশটি উদ্বেগ-অন্য লিব থেকে আলাদা হওয়া উচিত। এখন আমি কীভাবে এই সমস্যাটি নিয়েছিলাম তার মূল বিষয়গুলির কাছে - ওপি যেমন ঠিক বলেছেন:

মডেল (জেএস অংশ)

মডেল পর্যবেক্ষণের জন্য আমার গ্রহণযোগ্যতা প্রক্সি , এটি কার্যকর করার একমাত্র বুদ্ধিমান উপায়, আইএমএইচও। সম্পূর্ণ বৈশিষ্ট্যযুক্ত observerএটির নিজস্ব লাইব্রেরিটি প্রাপ্য, সুতরাং আমি object-observerসেই একমাত্র উদ্দেশ্যে লাইব্রেরি তৈরি করেছি ।

মডেল / গুলি কিছু উত্সর্গীকৃত এপিআই এর মাধ্যমে নিবন্ধিত হওয়া উচিত, এটি সেই পয়েন্ট যেখানে পোজগুলি Observableগুলি রূপান্তরিত হয় , এখানে কোনও শর্টকাট দেখতে পারে না। ডোম উপাদানগুলি যা একটি বাউন্ড ভিউ হিসাবে বিবেচিত হয় (নীচে দেখুন), প্রথমে মডেল / গুলিগুলির মান এবং তারপরে প্রতিটি ডেটা পরিবর্তনের পরে আপডেট করা হয়।

দর্শন (HTML অংশ)

আইএমএইচও, বাঁধাই প্রকাশের সবচেয়ে পরিষ্কার উপায়, গুণাবলীর মাধ্যমে। অনেকে আগে এটি করেছিলেন এবং অনেকে পরে করবেন, তাই এখানে কোনও খবর নেই, এটি করার এটি একটি সঠিক উপায়। আমার ক্ষেত্রে আমি নিম্নলিখিত বাক্য গঠন নিয়ে চলেছি: <span data-tie="modelKey:path.to.data => targerProperty"></span>তবে এটি কম গুরুত্বপূর্ণ। কি হল আমার কাছে গুরুত্বপূর্ণ, HTML এ কোন জটিল স্ক্রিপ্টিং সিনট্যাক্স - এই ভুল এই প্রোগ্রামটিতে হয়, আবার,।

সীমাবদ্ধ মতামত হিসাবে মনোনীত সমস্ত উপাদান প্রথমে সংগ্রহ করা উচিত। মডেলগুলি এবং দর্শনগুলির মধ্যে কিছু অভ্যন্তরীণ ম্যাপিং পরিচালনা করতে পারফরম্যান্সের পক্ষ থেকে আমার কাছে এটি অনিবার্য বলে মনে হচ্ছে, এটি একটি সঠিক ক্ষেত্রে বলে মনে হচ্ছে যেখানে রানটাইম লুক এবং আপডেটগুলি সংরক্ষণ করার জন্য মেমরি + কিছু পরিচালনার ত্যাগ করতে হবে।

মতামতগুলি প্রথমে মডেল থেকে আপডেট করা হয়, যদি পাওয়া যায় এবং পরে আমরা বলেছি যে মডেল পরিবর্তন হয়। আরও, MutationObserverগতিশীলভাবে যুক্ত / অপসারণ / পরিবর্তিত উপাদানগুলিতে প্রতিক্রিয়া (বাঁধাই / আবদ্ধ) করার জন্য পুরো ডিওএমটি পর্যবেক্ষণ করা উচিত । তদুপরি, আনবাউন্ড ব্ল্যাকহোলগুলি না ছেড়ে দেওয়ার জন্য এই সমস্তগুলি শ্যাডডোমে (অবশ্যই একটি খুলুন) প্রতিলিপি করা উচিত।

সুনির্দিষ্ট তালিকাগুলির তালিকাগুলি আরও প্রকৃতপক্ষে যেতে পারে তবে সেগুলি আমার মতে মূল প্রিন্সিপালরা ডেটা বাইন্ডিংকে কার্যকরভাবে ফিচারের সম্পূর্ণ ভারসাম্যতা এবং অন্য দিক থেকে বুদ্ধিমান সরলতার সাথে বাস্তবায়ন করত।

এবং এইভাবে, object-observerউপরে উল্লিখিত ছাড়াও , আমি প্রকৃতপক্ষে data-tierগ্রন্থাগারও লিখেছি , যা উপরোক্ত বর্ণিত ধারণাগুলির সাথে ডেটা বাইন্ডিং প্রয়োগ করে।


0

গত 7 বছরে জিনিসগুলি অনেকটা পরিবর্তিত হয়েছে, বেশিরভাগ ব্রাউজারে আমাদের কাছে দেশীয় ওয়েব উপাদান রয়েছে। আইএমও সমস্যার মূল উপাদানগুলির মধ্যে রাষ্ট্র ভাগ করে নেওয়া হয়, একবার আপনার যখন অবস্থা পরিবর্তন হয় এবং এর বিপরীতে ইউআই আপডেট করা তুচ্ছ হয়।

উপাদানগুলির মধ্যে ডেটা ভাগ করতে আপনি একটি স্টেটঅবার্সার ক্লাস তৈরি করতে পারেন এবং এটি থেকে আপনার ওয়েব উপাদানগুলি প্রসারিত করতে পারেন। একটি ন্যূনতম বাস্তবায়ন এরকম কিছু দেখায়:

// create a base class to handle state
class StateObserver extends HTMLElement {
	constructor () {
  	super()
    StateObserver.instances.push(this)
  }
	stateUpdate (update) {
  	StateObserver.lastState = StateObserver.state
    StateObserver.state = update
    StateObserver.instances.forEach((i) => {
    	if (!i.onStateUpdate) return
    	i.onStateUpdate(update, StateObserver.lastState)
    })
  }
}

StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}

// create a web component which will react to state changes
class CustomReactive extends StateObserver {
	onStateUpdate (state, lastState) {
  	if (state.someProp === lastState.someProp) return
    this.innerHTML = `input is: ${state.someProp}`
  }
}
customElements.define('custom-reactive', CustomReactive)

class CustomObserved extends StateObserver {
	connectedCallback () {
  	this.querySelector('input').addEventListener('input', (e) => {
    	this.stateUpdate({ someProp: e.target.value })
    })
  }
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
  <input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>

ফিডাল এখানে

আমি এই পদ্ধতির পছন্দ করি কারণ:

  • data-বৈশিষ্ট্য খুঁজে পেতে কোনও ডোম ট্র্যাভারসাল নেই
  • কোন অবজেক্ট.ওবাইজার (অবনমিত)
  • কোনও প্রক্সি নেই (যা কোনও হুক সরবরাহ করে তবে কোনও যোগাযোগ ব্যবস্থা নেই)
  • কোনও নির্ভরতা নেই, (আপনার টার্গেট ব্রাউজারগুলির উপর নির্ভর করে পলিফিল ব্যতীত)
  • এটি যুক্তিসঙ্গতভাবে কেন্দ্রীভূত এবং মডিউলার ... এইচটিএমএল-তে রাষ্ট্রের বর্ণনা দেয় এবং সর্বত্র শ্রোতাদের পেয়ে খুব দ্রুত অগোছালো হয়ে যায়।
  • এটা এক্সটেনসিবল এই মৌলিক বাস্তবায়নটি কোডের 20 টি লাইন, তবে আপনি সহজেই কিছু সুবিধা, অপরিবর্তনীয়তা এবং রাষ্ট্রীয় আকারের যাদুটিকে এটিকে কাজ করা সহজ করার জন্য তৈরি করতে পারেন।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.