Bootstrap is a front-end framework, a good thing for freeing web developers. It shows that the UI is very high-end, atmospheric and high-end. In theory, you don’t need to write a line of css. Just add the appropriate attributes to the tag.
KnockoutJS is a JavaScript-implemented MVVM framework. Very good. For example, after adding or decreasing the list data items, there is no need to refresh the entire control fragment or write JS addition and deletion nodes by yourself. Just define the template and attributes that meet its syntax definitions. Simply put, we only need to pay attention to the access to data.
1. Introduction to Knockout.js
1. Knockout.js and MVVM
Nowadays, various front-end frameworks are overwhelming and dazzling. Sometimes I have to sigh that as a programmer is really hard, there are always endless techniques to learn. When will it end, unless you transform! The sea of suffering is boundless, and whether it is the shore when you look back is up to you!
Knockout.js is a lightweight front-end framework based on MVVM mode. How light is it? According to the latest version v3.4.0 displayed on the official website, it is only 22kb. It can handle the binding between the data model and the interface DOM in a friendly manner. The most important thing is that its binding is bidirectional. That is to say, if the data model changes, the data on the interface DOM will also change accordingly. Conversely, if the data on the interface DOM changes, the data model will also change accordingly. This can greatly reduce the amount of our front-end code and make our interface easy to maintain, and we no longer have to write a lot of event monitoring data models and interface DOM changes. The blogger will illustrate these two points based on a usage example below.
Knockout.js official website: http://knockoutjs.com
Knockout.js open source address: https://github.com/knockout/knockout
MVVM mode: This is a design model for creating user interfaces. MVVM splits it into three pieces, namely Model, View, and ViewModel, Model is the data model, View is our view, and ViewModel is a view model, used to bind the data model and the dom elements on the view. If you have used WPF and Silverlight, understanding this should not be a problem; it is not a problem to have not used it. After reading this article, you will have a general understanding.
2. The simplest example
Generally speaking, if you use Knockout.js from scratch, you need to do at least the following four parts
2.1. Go to the official website to download the knockout.js file, and then quote it to the view page.
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
Note: knockout.js does not require jquery support. If your project requires jquery related operations, refer to jquery; otherwise, only reference the above files.
2.2. Define ViewModel
What is viewmodel? In fact, in js, it looks like a json object. We define a viewmodel:
var myViewModel = {Name: "Lilei",profession: "Software Engineer",};2.3. Define the tag that binds data-bind in the view view
<div> Name: <label data-bind="text:Name"></label><br />Profession: <input type="text" data-bind="textinput:Profession" /></div>
Note: Textinput is required for text corresponding to input tags, while text for text for ordinary tags is required.
2.4. Activate binding
After doing the above three steps, you also need to activate the binding of knockout
ko.applyBindings(myViewModel);
By doing these four parts, the simplest viewmodel data binding is basically implemented. Get the effect:
If you are careful enough, you will find that the ko.applyBindings() method has two parameters. The first is the viewmodel we need to bind, and what is the second? From ko.applyBindings(myViewModel); we can see that the second parameter is an optional parameter, which represents the scope of the tag bound to the viewmodel. For example, let's change the above code:
<div> Name: <label id="lb_name" data-bind="text:Name"></label><br />Profession: <input type="text" data-bind="textinput:Profession" /></div> ko.applyBindings(myViewModel,document.getElementById("lb_name"));Get the result:
From this we can see that the second parameter defines the scope of action of myViewModel, that is, only binding on the label of id="lb_name" will take effect. If the second parameter is a container label such as div, it means that the scope of the binding is all sub-labels below the div.
3. Monitoring attributes
As of the above four steps, we can't see any effect. What we see is nothing more than binding the data of a json object to the html tag. What's the point of doing this? Isn't it complicating simple problems? Don't worry, witness the miracle right away! As mentioned above, the most important significance of knockout lies in two-way binding. So how to achieve our two-way binding? The answer is monitoring attributes.
In knockout, there are three monitoring attributes in the core: Observables, DependentObservables, ObservableArray. The meaning of Observe is translated as observation and observation. If it feels inappropriate to say that it is an observation attribute or an observation attribute, we will call it a monitoring attribute for the time being.
3.1. Observables: Monitoring properties
Let's change the above example to this:
<head><meta name="viewport" content="width=device-width" /><title>Index3</title><script src="~/scripts/jquery-1.9.1.min.js"></script><script src="~/scripts/knockout/knockout-3.4.0.min.js"></script><body><div> Name: <label data-bind="text:Name"></label><br />Profession: <input type="text" data-bind="textinput:Profession" /></div><div><input type="text" id="txt_testobservable" /></div><script type="text/javascript">//1.Define ViewModelvar myViewModel = {Name: ko.observable("Lilei"),Profession: "Software Engineer",};//2. Activate the binding ko.applyBindings(myViewModel);$(function () {//Register textchange event $("#txt_testobservable").on("input", function () {myViewModel.Name($(this).val());});});</script></body>The meaning of this sentence is to add the Name property of the viewmodel to a monitoring property. The Name property must become a monitoring property. A magical thing will happen. Let's take a look at when we write myViewModel.:
Name has changed from the original property to a method, that is, once ko.observable() is added, the corresponding property will become a method. Therefore, the value and assignment of Name need to be handled using myViewModel.Name(). Let's take a look at the effect:
Code doubt: It is obvious that myViewModel.Name($(this).val()); This sentence assigns the value of the current text box to the Name property. Since the interface binds the Name property, the value in the label also changes accordingly. Or you would say that this can be done using the textchange event. As long as the value of the current text box is assigned to the label tag, this effect can be achieved, which is nothing. Indeed, your writing method can also achieve the purpose, but the significance of our monitoring attribute is that when the Name value is changed anywhere, the interface will change accordingly, without assigning values to the label tags in every place. In JS, you only need to focus on myViewModel.Name(). Isn't it very awesome ~~
3.2. DependentObservables: Monitor dependency properties
If you have read the monitoring attributes above, you are not satisfied yet? Let’s take a look at the use of monitoring dependency attributes.
Let's change the code and take a look:
<head><meta name="viewport" content="width=device-width" /><title>Index3</title><script src="~/scripts/jquery-1.9.1.min.js"></script><script src="~/scripts/knockout/knockout-3.4.0.min.js"></script></head><body><div> Name: <input type="text" data-bind="textinput:Name" /><br />Profession: <input type="text" data-bind="textinput:Profession" /><br /> />Description: <label data-bind="text:Des"></label></div><script type="text/javascript">//1.Definition ViewModelvar myViewModel = {Name: ko.observable("Lilei"),Profession: ko.observable("Software Engineer"),};myViewModel.Des = ko.dependentObservable(function () {return "I am named --" + myViewModel.Name() + ", occupation --" + myViewModel.Profession();});//2. Activate the binding ko.applyBindings(myViewModel);</script></body>Let's take a look at the effect:
Code doubt: by adding monitoring dependency attribute ko.dependentObservable(), the value of the Des attribute can be monitored at the same time to the changes in Name and Professor. If any of them changes, the Des-bound tag will trigger the change. The biggest advantage of this is to avoid the trouble of operating the dom by js, which is interesting.
3.3. ObservableArray; monitor arrays
In addition to the above two, ko also supports monitoring of array objects. Let's take a look at an example:
<head><meta name="viewport" content="width=device-width" /><title>Index3</title><script src="~/scripts/jquery-1.9.1.min.js"></script><script src="~/scripts/knockout/knockout-3.4.0.min.js"></script></head><body><div><select data-bind="options:deptArr,optionsText:'Name'"></select></div><div><input type="text" id="txt_testobservable" /><input type="button" id="btn_test" value="New department" /></div><script type="text/javascript">var deptArr = ko.observableArray([{ id: 1, Name: 'R&D Department' },{ id: 2, Name: 'Administrative Department' },{ id: 3, Name: 'Human Affairs Department' }]);var viewModel = {deptArr: deptArr,};ko.applyBindings(viewModel);var i=4;$(function () {$("#btn_test").on("click", function () {deptArr.push({ id: i++, Name: $("#txt_testobservable").val() });});});</script></body>Check out the effect:
Code doubt: The above method ko.observableArray() adds monitoring of array objects. That is to say, anywhere in js, as long as the array changes are made to the deptArr array object, the UI will be triggered to give the corresponding one. One thing to note is that the monitoring array is actually the monitored array object itself, and it cannot be monitored for changes in the child object properties in the array object. For example, we change the click event to this:
$(function () {$("#btn_test").on("click", function () {deptArr[1].Name = "aaa";});});Effect:
This shows that array monitoring actually monitors the array object itself, and will not monitor the changes in the attributes of elements in the array. If you really need to monitor the property changes of objects in the data, you need to use ko.observable() for the property of objects in the data, and the two are used together. If you are interested, you can try it.
4. Common data-bind attributes in ko
In the above, we used multiple data-bind attributes, so how many such data-bind attributes are there in knockout? Here we list some commonly used properties.
4.1. text and inputText
text, as the name implies, means text. This binding attribute is generally used to display text with tags such as <label>, <span>, <div>, etc. Of course, if you want, this binding can be used for any tag. It's basically nothing to say about using it. If ko.observable() is not used, it is a static binding, otherwise it is a dynamic binding.
inputText, the text of the input tag, is equivalent to the value attribute of the input tag.
<div> Name: <label data-bind="text:Name"></label><br />Profession: <input type="text" data-bind="textinput:Profession" /></div> //1.Define ViewModelvar myViewModel = {Name: ko.observable("Lilei"),Profession: "Software Engineer",};//2. Activate the binding ko.applyBindings(myViewModel);4.2. Value
This binding property is generally used for input tags, which is basically similar to the inputText above. But the value is more standardized.
Also used with value is a parameter valueUpdate, which indicates what operation the interface does when the value is updated. The main values of valueUpdate include change/keyup/keypress/afterkeydown, etc. It indicates the value of the viewmodel corresponding to the value when text changes, keyboard shrinking, keyboard pressing, keyboard pressing, keyboard pressing, etc.
Name: <input type="text" data-bind="value:Name,valueUpdate:'keyup'" /><br /> var myViewModel = {Name: ko.observable("Lilei"),};//2. Activate the binding ko.applyBindings(myViewModel);The above code indicates that the value attribute of the text box and the Name attribute of myViewModel are updated when the keyboard is closed.
4.3. Checked
Checked binding is generally used for checkbox, radio and other form elements that can be selected, and its corresponding value is bool type. The usage of value is basically similar, so I won't repeat it.
4.4. enable
enable binding is generally used to enable label elements, and is generally used to enable and disable form elements. Contrary to disabled, the corresponding value is also bool type.
<div><input type="text" data-bind="enable:IsMen"/></div><script type="text/javascript">//1.Define ViewModelvar myViewModel = {Name: ko.observable("Lilei"),Profession: ko.observable("Software Engineer"),Age: ko.observable(40),IsMen:ko.observable(true)};//2. Activate the binding ko.applyBindings(myViewModel);myViewModel.IsMen(false);</script>Since the IsMen property becomes false, all corresponding text boxes will display a disabled status.
4.5. disabled
Contrary to enable, the usage is similar to enable.
4.6. options
In the above, options were used when using select binding, which represents the set of options of the select tag, and the corresponding value is an array, representing the data source of this drop-down box. Monitoring of this data source can be enabled using observableArray. See above for usage.
4.7.html
Text binding is actually the setting and value of the tag innerText. Similarly, html binding is also the setting and value of the innerHTML. Its corresponding value is a html tag.
4.8. css
CSS binding is to add or remove one or more styles (classes) to the DOM element. Use format:
<style type="text/css">.testbold {background-color:powderblue;}</style> <div data-bind="css:{testbold:myViewModel.Name()=='Lilei'}">aaaa</div> var myViewModel = {Name: ko.observable("Lilei"),Profession: ko.observable("Software Engineer"),Age:ko.observable(40)};This div will display the background color.
If you need to add or remove multiple styles, just change them slightly, for example:
<div data-bind="css:{testbold:myViewModel.Name()=='Lilei',testborder:myViewModel.Profession()=='PHP Engineer'}">aaaa</div>4.9. Style
If the function of css binding is to dynamically add or remove class styles to the tag, then the function of style binding is to dynamically add or remove a certain style to the tag. for example:
<div data-bind="css:{background-color:myViewModel.Name()=='Lilei'?'red':'white'}">aaaa</div>If you add or remove multiple, how to use CSS binding
4.10, attr
Attr binding is mainly used to add and remove one or more attributes (including custom attributes) to the tag, and is similar to CSS.
4.11. Click
Click binding means adding a click event execution method to the corresponding DOM element. Can be used on any element.
<div><input type="button" value="test click binding" data-bind="click:ClickFunc" /></div> var myViewModel = {ClickFunc:function(){alert($(event.currentTarget).val());}};ko.applyBindings(myViewModel);event.currentTarget represents the DOM element currently clicked. Sometimes for simplicity, we directly use anonymous functions to bind, such as:
<div><input type="button" value="test click binding" data-bind="click:function(){alert('clicked');}" /></div>However, this way of writing js into html makes it difficult for bloggers to accept, and they feel that it is relatively inconvenient to maintain, especially when the logic in the click event is a bit complicated. Therefore, if it is not necessary, it is not recommended to write this anonymous function directly.
4.12. Others
For all bindings of data-bind, you can see the introduction on the official website, and I won’t list them one by one here. When you need it, just go to the official website to check it out. Take a look at all the bindings listed on the official website:
5. Transformation and relationship between Json objects and monitoring attributes
We know that in order to avoid direct presentation methods in different languages, in general, we use Json format data when interacting with the front-end and back-end. We use the data model retrieved from the back-end through http requests. To use some of our ko's features, we must convert these ordinary data models into ko's monitoring attributes; conversely, we use ko's monitoring attributes, and sometimes we need to convert these attributes into ordinary Json data and pass them to the background. So how to achieve this conversion?
5.1. Convert JSON object to ViewModel
For example, we take a Json object from the background, then turn it into our viewmodel, and then bind it to our interface DOM.
$.ajax({url: "/Home/GetData",type: "get",data: {},success: function (data, status) {var oJson = data;}});We send a request to the backend, take a json object, assign a value to oJson, and then we convert the oJson to viewmodel. The most intuitive way is to convert it manually. For example, we can do this:
var myViewModelJson = {DeptName: ko.observable(),DeptLevel: ko.observable(),DeptDesc:ko.observable()};ko.applyBindings(myViewModelJson);Then in the success requested by ajax
success: function (data, status) {var oJson = data;myViewModelJson.DeptName(oJson.DeptName);myViewModelJson.DeptLevel(oJson.DetpLevel);myViewModelJson.DeptDesc(oJson.DeptDesc);}In this way, through manual binding, the binding of the json object to the viewmodel is realized. The advantage of doing this is flexibility, the disadvantage is obvious, the amount of manual code is too large.
Fortunately, with our universal open source, there are always people who come up with a better way. We can use the knockout.Mapping component to help us convert the interface json object to viewmodel.
knockout.Mapping open source address: Download
Let's take a brief look at how it is used, or the example above. We do not need to implement the definition of any viewmodel. First, we need to refer to knockout.mapping.js
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script><script src="~/scripts/knockout/extensions/knockout.mapping-latest.js"></script>
Note: here knock.mapping-lastest.js must be placed behind knockout-3.4.0.min.js, otherwise ko.mapping cannot be called.
Then use it directly in the success function
success: function (data, status) {var myViewModelJson2 = ko.mapping.fromJS(data);ko.applyBindings(myViewModelJson2);}Let's see the effect:
Code doubt: The json object retrieved from the background through ajax request is conveniently converted into viewmodel through ko.mapping.fromJS(). Isn't it sharp? Of course, in addition to this usage, you can also update the existing viewmodel, and use it as follows:
var myViewModelJson = {DeptName: ko.observable(),DeptLevel: ko.observable(),DeptDesc:ko.observable()};ko.applyBindings(myViewModelJson);$(function () {$.ajax({url: "/Home/GetData",type: "get",data: {},success: function (data, status) {ko.mapping.fromJS(data, myViewModelJson)}});});In success, update the viewmodel of myViewModelJson according to the value of data.
5.2. Convert ViewModel to JSON object
The above mentioned that JSON objects are converted into viewmodel, so what should we do if we need to convert the viewmodel to Json objects and pass it to the backend?
There are two methods provided in knockout:
•ko.toJS(): Convert viewmodel to JSON object
•ko.toJSON(): Convert viewmodel to serialized Json string.
For example, our code is as follows:
$(function () {var oJson1 = ko.toJS(myViewModelJson);var oJson2 = ko.toJSON(myViewModelJson);});var myViewModelJson = {DeptName: ko.observable("R&D Department"),DeptLevel: ko.observable("2"),DeptDesc: ko.observable("Development Group")};ko.applyBindings(myViewModelJson);Then let's monitor the values of oJson1 and oJson2:
Code doubt: Through the above picture, it is easy to understand the difference between the two methods. It should be noted here that these two methods are built into ko and do not require the support of the mapping component.
6. Create your own data-bind attribute
I have talked about so much above, and I will introduce some binding and monitoring in knockout. So, sometimes, we need to customize our data-bind, such as: <label data-bind="myBind:Name"></label>. This requirement is especially useful when encapsulating components. Can it be implemented? sure.
In knockout, the ko.bindingHandlers property is provided to customize the data-bind property. Its syntax is as follows:
ko.bindingHandlers.MySelect = {init: function (element, valueAccessor, allBindingsAccessor, viewModel) {},update: function (element, valueAccessor, allBindingsAccessor, viewModel) {}};Just declare it like this, and then you can use custom data-bind in our html tag.
<div> <select data-bind="MySelect:$root"><option id="1">R&D Department</option><option id="2">Human Affairs Department</option><option id="3">Administrative Department</option></select></div>
MySelect is our custom binding property. $root can be understood as initialization for the time being (although this explanation is not rigorous, if there is a more reasonable explanation, please feel free to correct it).
Code doubt: The above ko.bindingHandlers can be used to simply implement custom binding properties. Two points need to be explained:
•init, as the name implies, initializes custom binding. It contains multiple parameters. The first two parameters are generally used more often. The first parameter represents the DOM element that initializes the custom binding, and the second parameter is generally used to pass the initialized parameters.
•update, update callback, when the corresponding monitoring attribute changes, this method will be entered. If no callback is required, this method can be undeclared.
Here, the blogger will briefly explain the use of custom bindings based on a drop-down box component MutiSelect that he had shared.
6.1. The simplest MutiSelect
Generally speaking, if we need to use ko to encapsulate some general components, we need to use our ko.bindingHandlers. The blogger will discuss how to use it in combination with the MutiSelect component.
First declare the customized ko.bindingHandlers, and initialize our select tag in the init method
ko.bindingHandlers.MySelect = {init: function (element, valueAccessor, allBindingsAccessor, viewModel) {$(element).multiselect();},update: function (element, valueAccessor, allBindingsAccessor, viewModel) {}};Then use it in the page tag
<div style="text-align:center;"> <select data-bind="MySelect:$root"><option id="1">R&D Department</option><option id="2">Human Affairs Department</option><option id="3">Administrative Department</option></select></div>
The last third part, Activate the binding
$(function () {var MultiSelect = {};ko.applyBindings(MultiSelect);});If you do not need to pass parameters, you only need to bind an empty viewmodel. Some people are puzzled, but the third part doesn’t feel that it’s practical. The blogger's understanding is that the DOM element needs to use data-bind to bind data, and ko binding must be enabled, which is ko.applyBindings() here.
Get the effect:
6.2. Parameter passing
The first step is to customize ko.bindingHandlers
ko.bindingHandlers.MySelect = {init: function (element, valueAccessor, allBindingsAccessor, viewModel) {var oParam = valueAccessor();$(element).multiselect(oParam);},update: function (element, valueAccessor, allBindingsAccessor, viewModel) {}};The second step is the same as above, use this custom binding in the html tag.
Step 3: Pass in parameters when activate the binding
$(function () {var MultiSelect = {enableClickableOptGroups: true,//Collapse grouping onChange: function (option, checked) {alert("Select Change");}};ko.applyBindings(MultiSelect);});Through these three steps, you can pass the parameters to the initialization of our MutiSelect:
Code queries: The second parameter of the init event, we said, its main function is to obtain the parameters transmitted from our viewmodel, but here we need to use it as a method. Why is it used so much remains to be studied!
2. The first example of adding, deleting, modifying and searching
At this point, the basic things have finally been laid out. I originally planned to complete them in one article, but I didn’t expect that the basic things will be expanded so much! The examples of adding, deleting, modifying and checking are included in the next article. BootstrapTable and KnockoutJS combine to realize the function of adding, deleting, modifying and checking [2]. Welcome to learn and communicate, and of course you are also welcome to recommend it!