问:
Modal not showing in when rendered in React component
What I'm trying to do: When I'm writing a project using React and Redux, I want to pop up a modal from RecordTaskPopUp component when the state isTimeOut of ManageTimer component is changed by a timer event (for readability purpose, I have directly defined isTimeOut to be true in the following code).

Problem: Modal not showing up on the page.

What I have done to find the problem:

I have changed .modal {display: block} in my css file but it still is not showing on the page.

I also try to render something else other than modal on my RecordTskPopUp component, it works perfectly fine. So I suppose the problem is with modal itself.

Paste the whole render snippet of RecordTaskPopUp from bootstrap document.

Can someone tell me what might be the possible cause of this problem? Thanks a lot!

```<code>class ManageTimer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isTimeOut: true
    }
  this.closePopUp = this.closePopUp.bind(this);
  }

  closePopUp() {
    this.setState({
    isTimeOut: false
    });
  }

  render() {
    return (
      {this.state.isTimeOut ?
      <RecordTaskPopUp
        closePopUp={this.closePopUp}/> :
      <p>There is still time remaining</p>
      }
    );
  }
}

const RecordTaskPopUp = ({closePopUp}) => {
   return (
      <div className="modal fade">
        <div className="modal-dialog" role="document">
          <div className="modal-content">
            <div className="modal-header">
              <h5 className="modal-title">Modal Header</h5>
              <button type="button" className="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true" onClick={closePopUp}>×</span>
              </button>
            </div>

            <div className="modal-body">
              <p> Modal Body</p>
            </div>

            <div className="modal-footer">
              <button type="button" className="btn btn-primary">Save changes</button>
              <button type="button" className="btn btn-secondary" data-dismiss="modal" onClick={closePopUp}>Close</button>
            </div>
          </div>
        </div>
      </div>
    </div>
   );
};
</code>```

答:
You can use

```<code>$('#mypopup').modal('toggle');
$('#mypopup').modal('show');
$('#mypopup').modal('hide');
</code>```

in your closePopUp()

In your case:

```<code>  closePopUp (){
     $('#mypopup').modal('hide');
  }
</code>```

Dont forget to add id="mypopup" to your outer div:

```<code><div className="modal fade" id="mypopup" tabIndex="-1" role="dialog">
</code>```

Here is a JSFiddle based on your code https://jsfiddle.net/rafahoro/dsjoayrt/15/

Hope it helps.

Edited/added:
 The modal methods are documented in bootstrap pages http://getbootstrap.com/javascript/#modals-methods

Body:
What I'm trying to do: When I'm writing a project using React and Redux, I want to pop up a modal from RecordTaskPopUp component when the state isTimeOut of ManageTimer component is changed by a timer event (for readability purpose, I have directly defined isTimeOut to be true in the following code).

Problem: Modal not showing up on the page.

What I have done to find the problem:

I have changed .modal {display: block} in my css file but it still is not showing on the page.

I also try to render something else other than modal on my RecordTskPopUp component, it works perfectly fine. So I suppose the problem is with modal itself.

Paste the whole render snippet of RecordTaskPopUp from bootstrap document.

Can someone tell me what might be the possible cause of this problem? Thanks a lot!

class ManageTimer extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isTimeOut: true
    }
  this.closePopUp = this.closePopUp.bind(this);
  }

  closePopUp() {
    this.setState({
    isTimeOut: false
    });
  }

  render() {
    return (
      {this.state.isTimeOut ?
      <RecordTaskPopUp
        closePopUp={this.closePopUp}/> :

There is still time remaining

      }
    );
  }
}

const RecordTaskPopUp = ({closePopUp}) => {
   return (

Modal Header

              <button type="button" className="close" data-dismiss="modal" aria-label="Close">
                ×
              </button>

 Modal Body

              <button type="button" className="btn btn-primary">Save changes</button>
              <button type="button" className="btn btn-secondary" data-dismiss="modal" onClick={closePopUp}>Close</button>

   );
};

Body:
You can use

$('#mypopup').modal('toggle');
$('#mypopup').modal('show');
$('#mypopup').modal('hide');

in your closePopUp()

In your case:

  closePopUp (){
     $('#mypopup').modal('hide');
  }

Dont forget to add id="mypopup" to your outer div:

<div className="modal fade" id="mypopup" tabIndex="-1" role="dialog">

Here is a JSFiddle based on your code https://jsfiddle.net/rafahoro/dsjoayrt/15/

Hope it helps.

Edited/added:
 The modal methods are documented in bootstrap pages http://getbootstrap.com/javascript/#modals-methods


来源: stackexchange

问:
last modified file date in node.js
I'm trying to retrieve the last modified date of a file on the server using node.js.

I've tried

```<code>file.lastModified;
</code>```

and

```<code>file.lastModifiedDate;
</code>```

both come back as undefined.

答:
Here you can get the file's last modified time in seconds.

```<code>fs.stat("filename.json", function(err, stats){
    let seconds = (new Date().getTime() - stats.mtime) / 1000;
    console.log(`File modified ${seconds} ago`);
});
</code>```

Outputs something like "File modified 300.9 seconds ago"

ContentLicense: CC BY-SA 3.0

Title: last modified file date in node.js

Body:
I'm trying to retrieve the last modified date of a file on the server using node.js.

I've tried

file.lastModified;

and

file.lastModifiedDate;

both come back as undefined.

Body:
Here you can get the file's last modified time in seconds.

fs.stat("filename.json", function(err, stats){
    let seconds = (new Date().getTime() - stats.mtime) / 1000;
    console.log(`File modified ${seconds} ago`);
});

Outputs something like "File modified 300.9 seconds ago"


问:
open webpage in firefox
i am not sure..is there any chance to open my webpage in firefox. for example i am browsing mywebsite using IE. when ever i click link of the page then automatically it will open in firefox. this option is not for all pages only for specified page.

thanks.

答:
Sorry, it's not possible from plain HTML to open a webpage in a different browser. You can, at most, open the page in a new window of the same browser.

However, what you ask is not completely impossible. You could write a browser plugin that handles links and runs the Firefox executable

ContentLicense: CC BY-SA 2.5

Title: open webpage in firefox


问:
UPDATED: How can I Insert a Json object inside a Json Array to SQLite
Good day, How to fetch this Json Response and insert it in Android SQLite.
Hope you will guide me how to fetch this Json object inside a Json Array inside a Object

```<code>{
  "error": false,
  "sl_summ": [
    {
      "sl_desc": "PA : Savings Account",
      "tr_date": "2015-08-17",
      "actual_balance": "483.67",
      "available_balance": "483.67"
    },
    {
      "sl_desc": "PA : Savings - Cash Bond",
      "tr_date": "2015-08-28",
      "actual_balance": "10129.43",
      "available_balance": "10129.43"
    }
  ]
}
</code>```

This my whole JSON response. the 1st Json Object(user) was successfully parse and inserted to database but the 2nd Json response(sl_summ) was unsuccessfully parse and was not inserted. and thats my problem.

```<code>{
  "error": false,
  "user": {
    "br_code": 12,
    "mem_id": 13,
    "username": "novalyn",
    "email": "gsac_tabaco@yahoo.com",
    "created_at": "2016-07-22 09:05:21"
  }
}
{
  "error": false,
  "sl_summ":
  [
    {
      "sl_desc": "PA : Savings Account",
      "tr_date": "2015-08-17",
      "actual_balance": "483.67",
      "available_balance": "483.67"
    },
    {
      "sl_desc": "PA : Savings - Cash Bond",
      "tr_date": "2015-08-28",
      "actual_balance": "10129.43",
      "available_balance": "10129.43"
    }
  ]
}
</code>```

This is the Logcat message

```<code>D/RegisterActivity: Login Response: {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}{"error":false,"sl_summ":[{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]}
07-05 16:19:15.068 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/ViewRootImpl@dd06ab4[LoginActivity]: dispatchDetachedFromWindow
07-05 16:19:15.083 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/InputTransport: Input channel destroyed: fd=76
07-05 16:19:15.084 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/RegisterActivity: Checking JSON Object{"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:19:15.085 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/TEST: -error attribute             : false
07-05 16:19:15.094 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SessionManager: User login session modified!
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -user object     : {"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -br_code         : 12
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -mem_id          : 13
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -username        : novalyn
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -email           : gsac_tabaco@yahoo.com
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -created at      : 2016-07-22 09:05:21
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: New member was inserted into table members: 13
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: BR CODE: 12
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Member ID: 13
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Username: novalyn
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Email: gsac_tabaco@yahoo.com
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Created at: 2016-07-22 09:05:21
07-05 16:19:15.118 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/sl_summ: JSON String                  : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:19:15.118 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/sl_summ: -error attribute             : false
07-05 16:19:15.119 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/TEST: org.json.JSONException: No value for sl_summ
</code>```

I noticed that only the 1st response was returned

```<code>D/sl_summ: JSON String : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
D/sl_summ: -error attribute             : false
D/TEST: org.json.JSONException: No value for sl_summ
</code>```

答:
Here is sample code to convert json string into a json object and access json array and its attributes.

Depending on your table schema in SQLite, you can either insert individual values in columns or persist complete JSON string, it depends on your requirements.

As you have 2 different json strings being processed and if you do not know which one is coming first then you can always check whether the JSONObject user or JSONArray sl_summ is present or not and depending on that you can handle them as follows. Note this is most crude of doing it, i have updated code just to get you going and there are many other way of checking.

```<code>import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

public static void jsonExample() {
    String loginString = "{\"error\":false, \"user\":{\"br_code\":12,\"mem_id\":13,\"username\":\"test\",\"email\":\"test@yahoo.com\",\"created_at\":\"2016-07-22 09:05:21\"}}";
    String jsonString = "{\"error\": false,\"sl_summ\":[{ \"sl_desc\": \"PA : Savings Account\", \"tr_date\": \"2015-08-17\", \"actual_balance\": \"483.67\", \"available_balance\": \"483.67\" }, { \"sl_desc\": \"PA : Savings - Cash Bond\", \"tr_date\": \"2015-08-28\", \"actual_balance\": \"10129.43\", \"available_balance\": \"10129.43\" } ] }";
    try {
        Log.d("TEST", "INPUT String                 : " + jsonString);
        JSONObject accountJSONObject = new JSONObject(jsonString);
        displaySubAttributes(accountJSONObject);
        Log.d("TEST", "INPUT String                 : " + loginString);
        JSONObject loginJSONObject = new JSONObject(loginString);
        displaySubAttributes(loginJSONObject);
    } catch (Exception exception) {
        Log.d("TEST", exception.toString());
    }
}

public static void displaySubAttributes(JSONObject jsonObject)  throws Exception {
    // read the json string into a json object
    Log.d("TEST", "JSON String                  : " + jsonObject.toString());

    // access individual json object thru jsonObject.get("FIELD_NAME")
    Log.d("TEST", "-error attribute             : " + jsonObject.get("error").toString());

    JSONArray slArray = jsonObject.optJSONArray("sl_summ");

    // Check if its login data i.e. user present
    if (!jsonObject.isNull("user") && slArray == null) {
        // handle user login data
        JSONObject userJSONObject = (JSONObject) jsonObject.get("user");
        Log.d("TEST", "User                         : " + userJSONObject.toString());
        Log.d("TEST", "-br_code attribute           : " + userJSONObject.get("br_code").toString());
        Log.d("TEST", "-mem_id attribute            : " + userJSONObject.get("mem_id").toString());
        Log.d("TEST", "-username attribute          : " + userJSONObject.get("username").toString());
        Log.d("TEST", "-email attribute             : " + userJSONObject.get("email").toString());
        Log.d("TEST", "-created_at attribute        : " + userJSONObject.get("created_at").toString());
        // Check if its account data i.e. sl_summ is present
    } else if (slArray != null && jsonObject.isNull("user")) {
        // handle account data
        JSONArray array = ((JSONArray)jsonObject.getJSONArray("sl_summ"));
        // access individual json array thru jsonObject.getJSONArray("FIELD_NAME")
        Log.d("TEST", "-sl_summ array               : " + jsonObject.getJSONArray("sl_summ").toString());
        for (int index=0; index<array.length(); index++) {
            JSONObject object = (JSONObject)array.get(index);
            Log.d("TEST", "-sl_desc attribute           : " + object.get("sl_desc").toString());
            Log.d("TEST", "-tr_date attribute           : " + object.get("tr_date").toString());
            Log.d("TEST", "-actual_balance attribute    : " + object.get("actual_balance").toString());
            Log.d("TEST", "-available_balance attribute : " + object.get("available_balance").toString());
            Log.d("TEST", "---------------------------------");
        }
    } else {
        // a new JSON string that doesn't have user or sl_summ as member variable so display it and write new handler code
        Log.d("TEST", "Unknown JSON String          : " + jsonObject.toString());
    }
}
</code>```

Sample Logs

```<code>07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: INPUT String                 : {"error": false,"sl_summ":[{ "sl_desc": "PA : Savings Account", "tr_date": "2015-08-17", "actual_balance": "483.67", "available_balance": "483.67" }, { "sl_desc": "PA : Savings - Cash Bond", "tr_date": "2015-08-28", "actual_balance": "10129.43", "available_balance": "10129.43" } ] }
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: JSON String                  : {"error":false,"sl_summ":[{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]}
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -error attribute             : false
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_summ array               : [{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_desc attribute           : PA : Savings Account
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -tr_date attribute           : 2015-08-17
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -actual_balance attribute    : 483.67
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -available_balance attribute : 483.67
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: ---------------------------------
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_desc attribute           : PA : Savings - Cash Bond
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -tr_date attribute           : 2015-08-28
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -actual_balance attribute    : 10129.43
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -available_balance attribute : 10129.43
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: ---------------------------------

07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: INPUT String                 : {"error":false, "user":{"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: JSON String                  : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -error attribute             : false
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: User                         : {"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -br_code attribute           : 12
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -mem_id attribute            : 13
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -username attribute          : test
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -email attribute             : test@yahoo.com
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -created_at attribute        : 2016-07-22 09:05:21
</code>```

Body:
Good day, How to fetch this Json Response and insert it in Android SQLite.
Hope you will guide me how to fetch this Json object inside a Json Array inside a Object

{
  "error": false,
  "sl_summ": [
    {
      "sl_desc": "PA : Savings Account",
      "tr_date": "2015-08-17",
      "actual_balance": "483.67",
      "available_balance": "483.67"
    },
    {
      "sl_desc": "PA : Savings - Cash Bond",
      "tr_date": "2015-08-28",
      "actual_balance": "10129.43",
      "available_balance": "10129.43"
    }
  ]
}

This my whole JSON response. the 1st Json Object(user) was successfully parse and inserted to database but the 2nd Json response(sl_summ) was unsuccessfully parse and was not inserted. and thats my problem.

{
  "error": false,
  "user": {
    "br_code": 12,
    "mem_id": 13,
    "username": "novalyn",
    "email": "gsac_tabaco@yahoo.com",
    "created_at": "2016-07-22 09:05:21"
  }
}
{
  "error": false,
  "sl_summ":
  [
    {
      "sl_desc": "PA : Savings Account",
      "tr_date": "2015-08-17",
      "actual_balance": "483.67",
      "available_balance": "483.67"
    },
    {
      "sl_desc": "PA : Savings - Cash Bond",
      "tr_date": "2015-08-28",
      "actual_balance": "10129.43",
      "available_balance": "10129.43"
    }
  ]
}

This is the Logcat message

D/RegisterActivity: Login Response: {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}{"error":false,"sl_summ":[{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]}
07-05 16:19:15.068 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/ViewRootImpl@dd06ab4[LoginActivity]: dispatchDetachedFromWindow
07-05 16:19:15.083 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/InputTransport: Input channel destroyed: fd=76
07-05 16:19:15.084 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/RegisterActivity: Checking JSON Object{"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:19:15.085 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/TEST: -error attribute             : false
07-05 16:19:15.094 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SessionManager: User login session modified!
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -user object     : {"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -br_code         : 12
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -mem_id          : 13
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -username        : novalyn
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -email           : gsac_tabaco@yahoo.com
07-05 16:19:15.095 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/USER: -created at      : 2016-07-22 09:05:21
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: New member was inserted into table members: 13
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: BR CODE: 12
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Member ID: 13
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Username: novalyn
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Email: gsac_tabaco@yahoo.com
07-05 16:19:15.117 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/SQLiteHandler: Created at: 2016-07-22 09:05:21
07-05 16:19:15.118 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/sl_summ: JSON String                  : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:19:15.118 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/sl_summ: -error attribute             : false
07-05 16:19:15.119 20514-20514/ph.coredev.johnjessbayutas.gsacmobileportal D/TEST: org.json.JSONException: No value for sl_summ

I noticed that only the 1st response was returned

D/sl_summ: JSON String : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"novalyn","email":"gsac_tabaco@yahoo.com","created_at":"2016-07-22 09:05:21"}}
D/sl_summ: -error attribute             : false
D/TEST: org.json.JSONException: No value for sl_summ

Body:
Here is sample code to convert json string into a json object and access json array and its attributes.

Depending on your table schema in SQLite, you can either insert individual values in columns or persist complete JSON string, it depends on your requirements.

As you have 2 different json strings being processed and if you do not know which one is coming first then you can always check whether the JSONObject user or JSONArray sl_summ is present or not and depending on that you can handle them as follows. Note this is most crude of doing it, i have updated code just to get you going and there are many other way of checking.

import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

public static void jsonExample() {
    String loginString = "{\"error\":false, \"user\":{\"br_code\":12,\"mem_id\":13,\"username\":\"test\",\"email\":\"test@yahoo.com\",\"created_at\":\"2016-07-22 09:05:21\"}}";
    String jsonString = "{\"error\": false,\"sl_summ\":[{ \"sl_desc\": \"PA : Savings Account\", \"tr_date\": \"2015-08-17\", \"actual_balance\": \"483.67\", \"available_balance\": \"483.67\" }, { \"sl_desc\": \"PA : Savings - Cash Bond\", \"tr_date\": \"2015-08-28\", \"actual_balance\": \"10129.43\", \"available_balance\": \"10129.43\" } ] }";
    try {
        Log.d("TEST", "INPUT String                 : " + jsonString);
        JSONObject accountJSONObject = new JSONObject(jsonString);
        displaySubAttributes(accountJSONObject);
        Log.d("TEST", "INPUT String                 : " + loginString);
        JSONObject loginJSONObject = new JSONObject(loginString);
        displaySubAttributes(loginJSONObject);
    } catch (Exception exception) {
        Log.d("TEST", exception.toString());
    }
}

public static void displaySubAttributes(JSONObject jsonObject)  throws Exception {
    // read the json string into a json object
    Log.d("TEST", "JSON String                  : " + jsonObject.toString());

    // access individual json object thru jsonObject.get("FIELD_NAME")
    Log.d("TEST", "-error attribute             : " + jsonObject.get("error").toString());

    JSONArray slArray = jsonObject.optJSONArray("sl_summ");

    // Check if its login data i.e. user present
    if (!jsonObject.isNull("user") && slArray == null) {
        // handle user login data
        JSONObject userJSONObject = (JSONObject) jsonObject.get("user");
        Log.d("TEST", "User                         : " + userJSONObject.toString());
        Log.d("TEST", "-br_code attribute           : " + userJSONObject.get("br_code").toString());
        Log.d("TEST", "-mem_id attribute            : " + userJSONObject.get("mem_id").toString());
        Log.d("TEST", "-username attribute          : " + userJSONObject.get("username").toString());
        Log.d("TEST", "-email attribute             : " + userJSONObject.get("email").toString());
        Log.d("TEST", "-created_at attribute        : " + userJSONObject.get("created_at").toString());
        // Check if its account data i.e. sl_summ is present
    } else if (slArray != null && jsonObject.isNull("user")) {
        // handle account data
        JSONArray array = ((JSONArray)jsonObject.getJSONArray("sl_summ"));
        // access individual json array thru jsonObject.getJSONArray("FIELD_NAME")
        Log.d("TEST", "-sl_summ array               : " + jsonObject.getJSONArray("sl_summ").toString());
        for (int index=0; index<array.length(); index++) {
            JSONObject object = (JSONObject)array.get(index);
            Log.d("TEST", "-sl_desc attribute           : " + object.get("sl_desc").toString());
            Log.d("TEST", "-tr_date attribute           : " + object.get("tr_date").toString());
            Log.d("TEST", "-actual_balance attribute    : " + object.get("actual_balance").toString());
            Log.d("TEST", "-available_balance attribute : " + object.get("available_balance").toString());
            Log.d("TEST", "---------------------------------");
        }
    } else {
        // a new JSON string that doesn't have user or sl_summ as member variable so display it and write new handler code
        Log.d("TEST", "Unknown JSON String          : " + jsonObject.toString());
    }
}

Sample Logs

07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: INPUT String                 : {"error": false,"sl_summ":[{ "sl_desc": "PA : Savings Account", "tr_date": "2015-08-17", "actual_balance": "483.67", "available_balance": "483.67" }, { "sl_desc": "PA : Savings - Cash Bond", "tr_date": "2015-08-28", "actual_balance": "10129.43", "available_balance": "10129.43" } ] }
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: JSON String                  : {"error":false,"sl_summ":[{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]}
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -error attribute             : false
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_summ array               : [{"sl_desc":"PA : Savings Account","tr_date":"2015-08-17","actual_balance":"483.67","available_balance":"483.67"},{"sl_desc":"PA : Savings - Cash Bond","tr_date":"2015-08-28","actual_balance":"10129.43","available_balance":"10129.43"}]
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_desc attribute           : PA : Savings Account
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -tr_date attribute           : 2015-08-17
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -actual_balance attribute    : 483.67
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -available_balance attribute : 483.67
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: ---------------------------------
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -sl_desc attribute           : PA : Savings - Cash Bond
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -tr_date attribute           : 2015-08-28
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -actual_balance attribute    : 10129.43
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: -available_balance attribute : 10129.43
07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: ---------------------------------

07-05 16:04:13.352 15643-15643/com.testing.test D/TEST: INPUT String                 : {"error":false, "user":{"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: JSON String                  : {"error":false,"user":{"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -error attribute             : false
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: User                         : {"br_code":12,"mem_id":13,"username":"test","email":"test@yahoo.com","created_at":"2016-07-22 09:05:21"}
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -br_code attribute           : 12
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -mem_id attribute            : 13
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -username attribute          : test
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -email attribute             : test@yahoo.com
07-05 16:04:13.353 15643-15643/com.testing.test D/TEST: -created_at attribute        : 2016-07-22 09:05:21


问:
Extjs 6 How to sum dates inside summaryType?
I have a table in postgresql.
There is a field type of "interval" and its name is 'time_duration'.
postgresql send to my extjs grid json like:

```<code>[{"id":"18","time_start":"2008-01-01 19:00:00+03","time_end":"2008-01-01 19:01:00+03","task":"test","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"00:01:00"},{"id":"20","time_start":"2008-01-01 19:00:00+03","time_end":"2008-01-01 20:00:00+03","task":"asdasdasdasdsdf asdas","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"01:00:00"},{"id":"21","time_start":"2008-01-01 12:00:00+03","time_end":"2008-01-01 14:00:00+03","task":"asdasdasdasdasd","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"02:00:00"},{"id":"19","time_start":"2008-01-01 18:21:51+03","time_end":"2008-01-01 18:22:00+03","task":"asdasd","task_type":"","date":"2017-07-02 00:00:00+03","task_result":"","username":"test_rakov","time_duration":"00:00:09"}]
</code>```

Id like to use Ext.grid.feature.GroupingSummary
When i use summaryType: 'sum' with dataIndex: 'time_duration' its return dates like a string and also add 0 at the start.
The summaryType gets in value parametr string "0Tue Jul 04 2017 00:01:00 GMT+0300 (RTZ 2 (зима))Tue Jul 04 2017 01:00:00 GMT+0300 (RTZ 2 (зима))Tue Jul 04 2017 02:00:00 GMT+0300 (RTZ 2 (зима))". So the dates from json are joined.
Id like to sum them. For example "time_duration":"01:00:00"+ "time_duration":"01:00:00" = "02:00:00".How to do it in right way? Mb change fields type in postgresl to something else? Help me please.

Here is my code:

```<code> Ext.require(['Ext.data.*', 'Ext.grid.*']);

        // Создаем model
        Ext.define('Users', {
            extend: 'Ext.data.Model',
            //idProperty: 'id',
            //idProperty: 'id',
            fields: [{
                    name: 'id',
                    type: 'int',
                    //mapping: 'id'
                },

                {
                    name:'time_duration',
                    type:'date',
                    dateFormat:'H:i:s'
                }
            ]
        });

        Ext.onReady(function() {
            // Создаем store
            var store = Ext.create('Ext.data.Store', {
                autoLoad: true,
                autoSync: true,
                model: 'Users',
                // Задает параметр для фильтрации подтаблиц myGroupingFeature
                groupField: 'date',
                groupDir: 'DESC',
                proxy: {
                    type: 'ajax',
                    url: 'test_rakov.php',
                    api: {
                        create: 'test_rakov.php?action=create',
                        read: 'test_rakov.php?action=read',
                        update: 'test_rakov.php?action=update',
                        destroy: 'test_rakov.php?action=delete'
                    },
                    reader: {
                        type: 'json',
                        // Данные получаемые от сервера, которые мы затем обрабатываем в таблице
                        rootProperty: 'dataFromServer'
                    },
                    writer: {
                        type: 'json',
                        encode: true,
                        rootProperty: 'dataUpdate',
                        allowSingle: false,
                        writeAllFields: true,
                        //root:'records'
                    },
                    actionMethods: {
                        create: 'GET',
                        read: 'GET',
                        update: 'GET',
                        destroy: 'GET'

                    }
                },
                listeners: {
                    write: function(store, operation) {
                        var record = operation.getRecords()[0],
                            name = Ext.String.capitalize(operation.action),
                            verb;

                        if (name == 'Destroy') {
                            verb = 'Destroyed';
                        } else {
                            verb = name + 'd';
                        }
                        //Ext.example.msg(name, Ext.String.format("{0} user: {1}", verb, record.getId()));
                    }
                }
            });

            // Отображает подтаблицы в таблице
            var myGroupingFeature = Ext.create('Ext.grid.feature.GroupingSummary', {
                 groupHeaderTpl: '{columnName}: {name} ({rows.length} задач)',
                hideGroupedHeader: false,
                // Сворачивать по умолчанию или нет
                startCollapsed: false
            });

            //  Данные для выбора типа задачи
            var storeCombo = new Ext.data.SimpleStore({
                fields: ["value"],
                data: [
                    ["Анализ регистраций в WebAdmin"],
                    ["AP -Анализ работы сервера"],
                    ["AP -Составление config файлов"],
                    ["Анализ заявок в СРМ"],
                    ["Встречи"],
                    ["Консультация сотрудников ОТП"],
                    ["Перекур"],
                    ["Программирование"],
                    ["Почтовая переписка"],
                    ["Другое"],
                ]
            });

            // Выбор типа задачи
            var combo = new Ext.form.ComboBox({
                store: storeCombo,
                editable: false,
                valueField: "value",
                displayField: "value",
            });

            var grid = Ext.create('Ext.grid.Panel', {
                columnLines: true,
                renderTo: document.body,
                // Редактирование таблицы
                plugins: {
                    ptype: 'cellediting',
                    clicksToEdit: 1
                },
                listeners: {
                    edit: function() {

                    }
                },
                width: '99,3%',
                // Высота на весь экран
                autoHeight: true,
                frame: true,
                title: 'Users',
                store: store,
                // Отображает подтаблицы в таблице
                features: [myGroupingFeature],
                iconCls: 'icon-user',
                columns: [{
                        text: 'id',
                        width: '2%',
                        sortable: true,
                        dataIndex: 'id',
                        renderer: function(v, meta, rec) {
                            return rec.phantom ? '' : v;
                        }
                    },
                    {
                        header: 'Задача',
                        width: '30%',
                        // sortable: true,
                        dataIndex: 'task',
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'textfield',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Время начала',
                        width: '5%',
                        // sortable: true,
                        dataIndex: 'time_start',
                        //format: 'H:i',
                        // Нужно для верного отображеия времени после редактирования в таблице
                        renderer: Ext.util.Format.dateRenderer('H:i'),
                        editor: {
                            completeOnEnter: true,
                            field: {
                                xtype: 'timefield',
                                format: 'Hi',
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                //minValue: '8:00',
                                //maxValue: '20:00',
                                increment: 720,
                                //anchor: '100%',
                                //allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Результат',
                        width: '30%',
                        // sortable: true,
                        dataIndex: 'task_result',
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'textfield',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                //anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },

                    {
                        header: 'Время конца',
                        width: '5%',
                        // sortable: true,
                        dataIndex: 'time_end',
                        //format: 'H:i',
                        // Нужно для верного отображеия времени после редактирования в таблице
                        renderer: Ext.util.Format.dateRenderer('H:i'),
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'timefield',
                                format: 'Hi',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                minValue: '8:00',
                                maxValue: '20:00',
                                increment: 30,
                                anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Дата',
                        width: 70,
                        // sortable: true,
                        dataIndex: 'date',
                        renderer: Ext.util.Format.dateRenderer('d/m/Y'),
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'datefield',
                                dateFormat: 'd/m/Y',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Длительность',
                        width: 60,
                        // sortable: true,
                        dataIndex: 'time_duration',
                        //xtype: 'datecolumn',
                        renderer: Ext.util.Format.dateRenderer('H:i:s'),
                        summaryType: 'sum',
                        //summaryType: function(f1){ console.log(f1); return;}
                        //summaryRenderer: Ext.util.Format.dateRenderer('H:i')

                        summaryRenderer: function(value, summaryData, dataIndex){
                            //console.log("val1= " + value);
                            var val2 = value.substring(1);
                            //console.log("val2= " + x);
                            var x = Ext.Date.format(val2, 'H:i:s');
                            //console.log (x);
                            //console.log( Ext.Date.format(val2, 'H:i:s'));
                             //console.log("tmpDate= " + tmpDate);
                            //return Ext.String.format('{0} student{1}', value, value !== 1 ? 's': '');
                        }

                    },
                    {
                        header: 'Тип задачи',
                        width: '20%',
                        dataIndex: 'task_type',
                        editor: combo
                    }
                ],
                dockedItems: [{
                    xtype: 'toolbar',
                    items: [{
                        text: 'Добавить задачу',
                        iconCls: 'icon-add',
                        handler: function() {
                            // Создаем новую задачу
                            // Для корректной работы с БД нужно задать ID новой строки, равной +1 от последней ID из таблицы.
                            var rec = new Users();

                            //rec.date = Ext.Date.format(new Date(), 'Y-m-d\\T00:00:00');
                            //rec.data.date = Ext.Date.format(new Date(), 'Y-m-d\\T00:00:00');
                            rec.set('date', new Date());
                            rec.set('time_start', new Date(),'H:i:s');

                            //rec.time_start = Ext.Date.format(new Date(), '2008-01-01\\TH:i:s');
                            //rec.data.time_start = Ext.Date.format(new Date(), '2008-01-01\\TH:i:s');
                            store.insert(0, rec);

                        }
                    }, '-', {
                        itemId: 'delete',
                        text: 'Удалить задачу',
                        iconCls: 'icon-delete',
                        disabled: false,
                        handler: function() {
                            var selection = grid.getView().getSelectionModel().getSelection()[0];
                            if (confirm('Вы действительно хотите удалить задачу №' + selection.id + " ?")) {
                                // Удлаяем
                                if (selection) {
                                    store.remove(selection);
                                }
                            }
                        }
                    }]
                }]
            });
        });
</code>```

答:
You can pass summaryType a function:

.... Alternatively, the summaryType can be a function definition. If
  this is the case, the function is called with two parameters: an array
  of records, and an array of field values to calculate the summary
  value.

http://docs.sencha.com/extjs/6.2.1/classic/Ext.grid.feature.GroupingSummary.html

So instead of:

```<code>summaryType: 'sum'
</code>```

You can use:

```<code>summaryType: function(records){
  // do your logic and return a value.
}
</code>```

Body:
I have a table in postgresql.
There is a field type of "interval" and its name is 'time_duration'.
postgresql send to my extjs grid json like:

[{"id":"18","time_start":"2008-01-01 19:00:00+03","time_end":"2008-01-01 19:01:00+03","task":"test","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"00:01:00"},{"id":"20","time_start":"2008-01-01 19:00:00+03","time_end":"2008-01-01 20:00:00+03","task":"asdasdasdasdsdf asdas","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"01:00:00"},{"id":"21","time_start":"2008-01-01 12:00:00+03","time_end":"2008-01-01 14:00:00+03","task":"asdasdasdasdasd","task_type":"","date":"2017-07-03 00:00:00+03","task_result":"asdasd","username":"test_rakov","time_duration":"02:00:00"},{"id":"19","time_start":"2008-01-01 18:21:51+03","time_end":"2008-01-01 18:22:00+03","task":"asdasd","task_type":"","date":"2017-07-02 00:00:00+03","task_result":"","username":"test_rakov","time_duration":"00:00:09"}]

Id like to use Ext.grid.feature.GroupingSummary
When i use summaryType: 'sum' with dataIndex: 'time_duration' its return dates like a string and also add 0 at the start.
The summaryType gets in value parametr string "0Tue Jul 04 2017 00:01:00 GMT+0300 (RTZ 2 (зима))Tue Jul 04 2017 01:00:00 GMT+0300 (RTZ 2 (зима))Tue Jul 04 2017 02:00:00 GMT+0300 (RTZ 2 (зима))". So the dates from json are joined.
Id like to sum them. For example "time_duration":"01:00:00"+ "time_duration":"01:00:00" = "02:00:00".How to do it in right way? Mb change fields type in postgresl to something else? Help me please.

Here is my code:

 Ext.require(['Ext.data.*', 'Ext.grid.*']);

        // Создаем model
        Ext.define('Users', {
            extend: 'Ext.data.Model',
            //idProperty: 'id',
            //idProperty: 'id',
            fields: [{
                    name: 'id',
                    type: 'int',
                    //mapping: 'id'
                },

                {
                    name:'time_duration',
                    type:'date',
                    dateFormat:'H:i:s'
                }
            ]
        });

        Ext.onReady(function() {
            // Создаем store
            var store = Ext.create('Ext.data.Store', {
                autoLoad: true,
                autoSync: true,
                model: 'Users',
                // Задает параметр для фильтрации подтаблиц myGroupingFeature
                groupField: 'date',
                groupDir: 'DESC',
                proxy: {
                    type: 'ajax',
                    url: 'test_rakov.php',
                    api: {
                        create: 'test_rakov.php?action=create',
                        read: 'test_rakov.php?action=read',
                        update: 'test_rakov.php?action=update',
                        destroy: 'test_rakov.php?action=delete'
                    },
                    reader: {
                        type: 'json',
                        // Данные получаемые от сервера, которые мы затем обрабатываем в таблице
                        rootProperty: 'dataFromServer'
                    },
                    writer: {
                        type: 'json',
                        encode: true,
                        rootProperty: 'dataUpdate',
                        allowSingle: false,
                        writeAllFields: true,
                        //root:'records'
                    },
                    actionMethods: {
                        create: 'GET',
                        read: 'GET',
                        update: 'GET',
                        destroy: 'GET'

                    }
                },
                listeners: {
                    write: function(store, operation) {
                        var record = operation.getRecords()[0],
                            name = Ext.String.capitalize(operation.action),
                            verb;

                        if (name == 'Destroy') {
                            verb = 'Destroyed';
                        } else {
                            verb = name + 'd';
                        }
                        //Ext.example.msg(name, Ext.String.format("{0} user: {1}", verb, record.getId()));
                    }
                }
            });

            // Отображает подтаблицы в таблице
            var myGroupingFeature = Ext.create('Ext.grid.feature.GroupingSummary', {
                 groupHeaderTpl: '{columnName}: {name} ({rows.length} задач)',
                hideGroupedHeader: false,
                // Сворачивать по умолчанию или нет
                startCollapsed: false
            });

            //  Данные для выбора типа задачи
            var storeCombo = new Ext.data.SimpleStore({
                fields: ["value"],
                data: [
                    ["Анализ регистраций в WebAdmin"],
                    ["AP -Анализ работы сервера"],
                    ["AP -Составление config файлов"],
                    ["Анализ заявок в СРМ"],
                    ["Встречи"],
                    ["Консультация сотрудников ОТП"],
                    ["Перекур"],
                    ["Программирование"],
                    ["Почтовая переписка"],
                    ["Другое"],
                ]
            });

            // Выбор типа задачи
            var combo = new Ext.form.ComboBox({
                store: storeCombo,
                editable: false,
                valueField: "value",
                displayField: "value",
            });

            var grid = Ext.create('Ext.grid.Panel', {
                columnLines: true,
                renderTo: document.body,
                // Редактирование таблицы
                plugins: {
                    ptype: 'cellediting',
                    clicksToEdit: 1
                },
                listeners: {
                    edit: function() {

                    }
                },
                width: '99,3%',
                // Высота на весь экран
                autoHeight: true,
                frame: true,
                title: 'Users',
                store: store,
                // Отображает подтаблицы в таблице
                features: [myGroupingFeature],
                iconCls: 'icon-user',
                columns: [{
                        text: 'id',
                        width: '2%',
                        sortable: true,
                        dataIndex: 'id',
                        renderer: function(v, meta, rec) {
                            return rec.phantom ? '' : v;
                        }
                    },
                    {
                        header: 'Задача',
                        width: '30%',
                        // sortable: true,
                        dataIndex: 'task',
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'textfield',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Время начала',
                        width: '5%',
                        // sortable: true,
                        dataIndex: 'time_start',
                        //format: 'H:i',
                        // Нужно для верного отображеия времени после редактирования в таблице
                        renderer: Ext.util.Format.dateRenderer('H:i'),
                        editor: {
                            completeOnEnter: true,
                            field: {
                                xtype: 'timefield',
                                format: 'Hi',
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                //minValue: '8:00',
                                //maxValue: '20:00',
                                increment: 720,
                                //anchor: '100%',
                                //allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Результат',
                        width: '30%',
                        // sortable: true,
                        dataIndex: 'task_result',
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'textfield',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                //anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },

                    {
                        header: 'Время конца',
                        width: '5%',
                        // sortable: true,
                        dataIndex: 'time_end',
                        //format: 'H:i',
                        // Нужно для верного отображеия времени после редактирования в таблице
                        renderer: Ext.util.Format.dateRenderer('H:i'),
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'timefield',
                                format: 'Hi',
                                enableKeyEvents: true,
                                listeners: {
                                    keydown: function(field, e) {
                                        if (e.getKey() == e.ENTER) {
                                            field = grid.getSelectionModel().getCurrentPosition().rowIdx;
                                            grid.getView().focusRow(field);
                                        }
                                    }
                                },
                                //name: 'timeStart1',
                                //fieldLabel: 'Time In',
                                minValue: '8:00',
                                maxValue: '20:00',
                                increment: 30,
                                anchor: '100%',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Дата',
                        width: 70,
                        // sortable: true,
                        dataIndex: 'date',
                        renderer: Ext.util.Format.dateRenderer('d/m/Y'),
                        editor: {
                            completeOnEnter: false,
                            field: {
                                xtype: 'datefield',
                                dateFormat: 'd/m/Y',
                                allowBlank: false
                            }
                        }
                    },
                    {
                        header: 'Длительность',
                        width: 60,
                        // sortable: true,
                        dataIndex: 'time_duration',
                        //xtype: 'datecolumn',
                        renderer: Ext.util.Format.dateRenderer('H:i:s'),
                        summaryType: 'sum',
                        //summaryType: function(f1){ console.log(f1); return;}
                        //summaryRenderer: Ext.util.Format.dateRenderer('H:i')

                        summaryRenderer: function(value, summaryData, dataIndex){
                            //console.log("val1= " + value);
                            var val2 = value.substring(1);
                            //console.log("val2= " + x);
                            var x = Ext.Date.format(val2, 'H:i:s');
                            //console.log (x);
                            //console.log( Ext.Date.format(val2, 'H:i:s'));
                             //console.log("tmpDate= " + tmpDate);
                            //return Ext.String.format('{0} student{1}', value, value !== 1 ? 's': '');
                        }

                    },
                    {
                        header: 'Тип задачи',
                        width: '20%',
                        dataIndex: 'task_type',
                        editor: combo
                    }
                ],
                dockedItems: [{
                    xtype: 'toolbar',
                    items: [{
                        text: 'Добавить задачу',
                        iconCls: 'icon-add',
                        handler: function() {
                            // Создаем новую задачу
                            // Для корректной работы с БД нужно задать ID новой строки, равной +1 от последней ID из таблицы.
                            var rec = new Users();

                            //rec.date = Ext.Date.format(new Date(), 'Y-m-d\\T00:00:00');
                            //rec.data.date = Ext.Date.format(new Date(), 'Y-m-d\\T00:00:00');
                            rec.set('date', new Date());
                            rec.set('time_start', new Date(),'H:i:s');

                            //rec.time_start = Ext.Date.format(new Date(), '2008-01-01\\TH:i:s');
                            //rec.data.time_start = Ext.Date.format(new Date(), '2008-01-01\\TH:i:s');
                            store.insert(0, rec);

                        }
                    }, '-', {
                        itemId: 'delete',
                        text: 'Удалить задачу',
                        iconCls: 'icon-delete',
                        disabled: false,
                        handler: function() {
                            var selection = grid.getView().getSelectionModel().getSelection()[0];
                            if (confirm('Вы действительно хотите удалить задачу №' + selection.id + " ?")) {
                                // Удлаяем
                                if (selection) {
                                    store.remove(selection);
                                }
                            }
                        }
                    }]
                }]
            });
        });

Body:
You can pass summaryType a function:

.... Alternatively, the summaryType can be a function definition. If
  this is the case, the function is called with two parameters: an array
  of records, and an array of field values to calculate the summary
  value.

http://docs.sencha.com/extjs/6.2.1/classic/Ext.grid.feature.GroupingSummary.html

So instead of:

summaryType: 'sum'

You can use:

summaryType: function(records){
  // do your logic and return a value.
}


问:
javascript form validation using php
checkEmpty validation is not working. functions are not executing in the PHP file. I tried below code please help me to understand where I am wrong.

My Code in my index.php file.

```<code><div class="main_wrapper">
    <form name="myform" method="post" action="test1.php">
        <div class="head_wrapper">
            Rollno : <input type="text" name="id" onblur="checkEmpty('id')" value="<?php echo $id; ?>"/></br></br>
            Name   : <input type="text" name="name" onblur="checkEmpty('name')" value="
                            <?php echo $name; ?>"/></br></br>
            Email  : <input type="text" name="email" onblur="checkEmpty('email')"
                            value="<?php echo $email; ?>"/></br></br>
            Phone  : <input type="number" name="phone" onblur="checkEmpty('phone')"
                            value="<?php echo $phone; ?>"/></br></br>
            Address : <input type="text" name="address" onblur="checkEmpty('address')"
                             value="<?php echo $address; ?>"/></br></br>
            Dept_code: <input type="text" name="dept_code"
                              onblur="checkEmpty('dept_code')" value="<?php echo $dept_code; ?>"/></br>
            </br>
        </div>
        <div class="foot_wrapper">
            <input type="submit" name="insert" value="Addinfo"/>
            <input type="submit" name="update" value="Modify"/>
            <input type="submit" name="delete" value="Delete"/>
            <input type="submit" name="search" value="Find"/>
            <input type="submit" name="display" value="Display"/>
        </div>
    </form>
</div>
</body>
<script src="validation.js">
    function checkEmpty(field)
    {
        var fn = document.getElementById(field).value;
        if (fn == "" || fn = null)
        {
            alert("Fill the box");

        }
    }

    function validEmail(email)
    {
        var fn = document.getElementById(email).value;
        var format = /.+@.+/;
        if (!fn.match(format))
        {
            alert("Enter valid mail");
        }
    }
</script>
</code>```

答:
First: you need to put id on your input tags if you gonna use the getElementById

```<code><input type="text" name="id" onblur="checkEmpty('id')" value="<?php echo $id; ?>" id="id" /> //it is better to use id the same as the name
</code>```

Second: inside the checkEmpty function you need to fix the

```<code>if(fn==""||fn=null) //change the fn=null to fn == null
{
  alert("Fill the box");
}
</code>```

third: I wouldn't recommend using the alert("Fill the box") because you are using the onblur method, once you try to skip the field for id/Rollno

 1. The focus will be on the next input which is for the 'Name'.

 2. The alert will be triggered and will say to 'fill the box' for the 'Rollno'

 3. Once the alert shows, it will also trigger the onblur method for the 'Name'

4.Then it will loop showing the alert

I would recommend to put a hidden span that will act as an alert to the user, which will show if the user left the field blank

```<code><input type="text" name="id" onblur="checkEmpty('id')" value="" id="id"/><span id="alertForId" hidden="" class="alerts">Fill the this field first.</span></br></br>
</code>```

and your checkEmpty function will somehow look like:

```<code>function checkEmpty(field)
{
console.log(field);
 var fn=document.getElementById(field).value;
 if(fn==""||fn==null)
 {
    if(field == "id")
    {
        $("#alertForId").show();
    }
 }else $(".alerts").hide();
}
</code>```

I put a class 'alerts' to the span to hide them in case the field is not empty, but it will hide all the spans. Just try to configure the code an hope it will help you.

Here is the code configured based from your code:

```<code><div class="main_wrapper">
    <form name="myform" method="post" action="index.php">
    <div class="head_wrapper">
         Rollno : <input type="text" name="id" id="id" onblur="checkEmpty('id')" value=""/><span id="alertForId" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Name   : <input type="text" name="name" id="name" onblur="checkEmpty('name')" value=""/><span id="alertForName" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Email  : <input type="text" name="email" id="email" onblur="checkEmpty('email')" value=""/><span id="alertForEmail" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Phone  : <input type="number" name="phone" id="phone" onblur="checkEmpty('phone')" value=""/><span id="alertForPhone" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Address : <input type="text" name="address" id="address" onblur="checkEmpty('address')" value=""/><span id="alertForAddress" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Dept_code: <input type="text" name="dept_code" id="dept_code" onblur="checkEmpty('dept_code')" value=""/><span id="alertForIdDeptCode" class="alerts" hidden="">Fill the this field first.</span></br>
     </br>
     </div>
     <div class="foot_wrapper">
     <input type="submit" name="insert" value="Addinfo"/>
     <input type="submit" name="update" value="Modify"/>
     <input type="submit" name="delete" value="Delete"/>
     <input type="submit" name="search" value="Find"/>
     <input type="submit" name="display" value="Display"/>

     </div>

     </form>

     </div>
     <script type="text/javascript" src="../jquery.js"></script>
     <script type="text/javascript">
     // validation.js is here
      //validation
     function checkEmpty(field)
     {
        var fn=document.getElementById(field).value;
     if(fn==""||fn==null)
     {
         if(field == "id")
             $("#alertForId").show();
         if(field == "name")
             $("#alertForName").show();
         if(field == "email")
             $("#alertForEmail").show();
         if(field == "phone")
             $("#alertForPhone").show();
         if(field == "address")
             $("#alertForAddress").show();
         if(field == "dept_code")
             $("#alertForIdDeptCode").show();

     } else{
    if(field == "id")
        $("#alertForId").hide();
    if(field == "name")
        $("#alertForName").hide();
    if(field == "email")
        $("#alertForEmail").hide();
    if(field == "phone")
        $("#alertForPhone").hide();
    if(field == "address")
        $("#alertForAddress").hide();
    if(field == "dept_code")
        $("#alertForIdDeptCode").hide();
  }
   }
   function validEmail(email)
   {
         var fn=document.getElementById(email).value;
         var format=/.+@.+/;
       if(!fn.match(format))
       {
       alert("Enter valid mail");
       }
   }
   </script>
   </body>'
</code>```

changes I made:

I just put your javascript inside the same page

Just link a jquery.js

Title: javascript form validation using php

Body:
checkEmpty validation is not working. functions are not executing in the PHP file. I tried below code please help me to understand where I am wrong.

My Code in my index.php file.

    <form name="myform" method="post" action="test1.php">

            Rollno : <input type="text" name="id" onblur="checkEmpty('id')" value="<?php echo $id; ?>"/>

            Name   : <input type="text" name="name" onblur="checkEmpty('name')" value="
                            <?php echo $name; ?>"/>

            Email  : <input type="text" name="email" onblur="checkEmpty('email')"
                            value="<?php echo $email; ?>"/>

            Phone  : <input type="number" name="phone" onblur="checkEmpty('phone')"
                            value="<?php echo $phone; ?>"/>

            Address : <input type="text" name="address" onblur="checkEmpty('address')"
                             value="<?php echo $address; ?>"/>

            Dept_code: <input type="text" name="dept_code"
                              onblur="checkEmpty('dept_code')" value="<?php echo $dept_code; ?>"/>

            <input type="submit" name="insert" value="Addinfo"/>
            <input type="submit" name="update" value="Modify"/>
            <input type="submit" name="delete" value="Delete"/>
            <input type="submit" name="search" value="Find"/>
            <input type="submit" name="display" value="Display"/>

    </form>

Body:
First: you need to put id on your input tags if you gonna use the getElementById

<input type="text" name="id" onblur="checkEmpty('id')" value="<?php echo $id; ?>" id="id" /> //it is better to use id the same as the name

Second: inside the checkEmpty function you need to fix the

if(fn==""||fn=null) //change the fn=null to fn == null
{
  alert("Fill the box");
}

third: I wouldn't recommend using the alert("Fill the box") because you are using the onblur method, once you try to skip the field for id/Rollno

 1. The focus will be on the next input which is for the 'Name'.

 2. The alert will be triggered and will say to 'fill the box' for the 'Rollno'

 3. Once the alert shows, it will also trigger the onblur method for the 'Name'

4.Then it will loop showing the alert

I would recommend to put a hidden span that will act as an alert to the user, which will show if the user left the field blank

<input type="text" name="id" onblur="checkEmpty('id')" value="" id="id"/><span id="alertForId" hidden="" class="alerts">Fill the this field first.</span></br></br>

and your checkEmpty function will somehow look like:

function checkEmpty(field)
{
console.log(field);
 var fn=document.getElementById(field).value;
 if(fn==""||fn==null)
 {
    if(field == "id")
    {
        $("#alertForId").show();
    }
 }else $(".alerts").hide();
}

I put a class 'alerts' to the span to hide them in case the field is not empty, but it will hide all the spans. Just try to configure the code an hope it will help you.

Here is the code configured based from your code:

<div class="main_wrapper">
    <form name="myform" method="post" action="index.php">
    <div class="head_wrapper">
         Rollno : <input type="text" name="id" id="id" onblur="checkEmpty('id')" value=""/><span id="alertForId" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Name   : <input type="text" name="name" id="name" onblur="checkEmpty('name')" value=""/><span id="alertForName" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Email  : <input type="text" name="email" id="email" onblur="checkEmpty('email')" value=""/><span id="alertForEmail" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Phone  : <input type="number" name="phone" id="phone" onblur="checkEmpty('phone')" value=""/><span id="alertForPhone" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Address : <input type="text" name="address" id="address" onblur="checkEmpty('address')" value=""/><span id="alertForAddress" class="alerts" hidden="">Fill the this field first.</span></br></br>
         Dept_code: <input type="text" name="dept_code" id="dept_code" onblur="checkEmpty('dept_code')" value=""/><span id="alertForIdDeptCode" class="alerts" hidden="">Fill the this field first.</span></br>
     </br>
     </div>
     <div class="foot_wrapper">
     <input type="submit" name="insert" value="Addinfo"/>
     <input type="submit" name="update" value="Modify"/>
     <input type="submit" name="delete" value="Delete"/>
     <input type="submit" name="search" value="Find"/>
     <input type="submit" name="display" value="Display"/>

     </div>

     </form>

     </div>
     <script type="text/javascript" src="../jquery.js"></script>
     <script type="text/javascript">
     // validation.js is here
      //validation
     function checkEmpty(field)
     {
        var fn=document.getElementById(field).value;
     if(fn==""||fn==null)
     {
         if(field == "id")
             $("#alertForId").show();
         if(field == "name")
             $("#alertForName").show();
         if(field == "email")
             $("#alertForEmail").show();
         if(field == "phone")
             $("#alertForPhone").show();
         if(field == "address")
             $("#alertForAddress").show();
         if(field == "dept_code")
             $("#alertForIdDeptCode").show();

     } else{
    if(field == "id")
        $("#alertForId").hide();
    if(field == "name")
        $("#alertForName").hide();
    if(field == "email")
        $("#alertForEmail").hide();
    if(field == "phone")
        $("#alertForPhone").hide();
    if(field == "address")
        $("#alertForAddress").hide();
    if(field == "dept_code")
        $("#alertForIdDeptCode").hide();
  }
   }
   function validEmail(email)
   {
         var fn=document.getElementById(email).value;
         var format=/.+@.+/;
       if(!fn.match(format))
       {
       alert("Enter valid mail");
       }
   }
   </script>
   </body>'

changes I made:

I just put your javascript inside the same page

Just link a jquery.js


问:
Using Rails 5 + Devise, I can't get the models to associate with each other
Originally I had a Joke.rb model that belonged to User model. Joke table had :joke, :author. It worked perfectly when using @joke = current_user.jokes.new(joke_params) but I took the :author out of the Joke model and made it its own model so I can make vanity url's / dynamic routes for each author, when a joke is created by the user. Here's what I have now:

User Model:

has_many :jokes

Joke Model:

belongs_to :user
 has_one :author

Author Model:

has_many :jokes

Here's my Schema:

```<code>ActiveRecord::Schema.define(version: 20170703173447) do

  create_table "authors", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "jokes", force: :cascade do |t|
    t.string   "joke"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

end
</code>```

And here's my Joke controller:

```<code>class JokesController < ApplicationController
  before_action :set_joke, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index]

  def index
    @joke = Joke.order("Random()").first
  end

  def my_jokes
    @jokes = current_user.jokes.all
  end

  def new
    @joke = current_user.jokes.new
  end

  def create
    @joke = current_user.jokes.new(joke_params)
    if @joke.save
      redirect_to root_path, notice: 'Joke was successfully added!'
    else
      render :new
    end
  end

  def update
    if @joke.update(joke_params)
      redirect_to root_path, notice: 'Joke was successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    @joke.destroy
    redirect_to my_jokes_path, notice: 'Joke was successfully deleted.'
  end

  def edit
  end

  def about
  end

  private

  def joke_params
    params.require(:joke).permit(:joke, :name)
  end

  def set_joke
    @joke = Joke.find(params[:id])
  end

end
</code>```

In rails console, when calling Author or Joke, neither are associated with each other.

I've tried so many different things and I can't get it to work. I've followed many answers from semi-related questions here and just through tutorials, but I suck. Please help, thanks! :)

REPO: https://github.com/joshzandman/random-joke

答:
NoMethodError: undefined method jokes' for Class:0x007fbefa5c4160

You are doing it wrong by calling Author.jokes. You should use joins or includes

```<code>Author.joins(:jokes)
</code>```

or

```<code>Author.includes(:jokes)
</code>```

Also, your associations aren't right. You have has_many :jokes in Author which is right but you have has_one :author in Joke which isn't right. Perhaps you should have belongs_to :author. I recommend you to read  associations

Body:
Originally I had a Joke.rb model that belonged to User model. Joke table had :joke, :author. It worked perfectly when using @joke = current_user.jokes.new(joke_params) but I took the :author out of the Joke model and made it its own model so I can make vanity url's / dynamic routes for each author, when a joke is created by the user. Here's what I have now:

User Model:

has_many :jokes

Joke Model:

belongs_to :user
 has_one :author

Author Model:

has_many :jokes

Here's my Schema:

ActiveRecord::Schema.define(version: 20170703173447) do

  create_table "authors", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "jokes", force: :cascade do |t|
    t.string   "joke"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer  "user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end

end

And here's my Joke controller:

class JokesController < ApplicationController
  before_action :set_joke, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index]

  def index
    @joke = Joke.order("Random()").first
  end

  def my_jokes
    @jokes = current_user.jokes.all
  end

  def new
    @joke = current_user.jokes.new
  end

  def create
    @joke = current_user.jokes.new(joke_params)
    if @joke.save
      redirect_to root_path, notice: 'Joke was successfully added!'
    else
      render :new
    end
  end

  def update
    if @joke.update(joke_params)
      redirect_to root_path, notice: 'Joke was successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    @joke.destroy
    redirect_to my_jokes_path, notice: 'Joke was successfully deleted.'
  end

  def edit
  end

  def about
  end

  private

  def joke_params
    params.require(:joke).permit(:joke, :name)
  end

  def set_joke
    @joke = Joke.find(params[:id])
  end

end

In rails console, when calling Author or Joke, neither are associated with each other.

I've tried so many different things and I can't get it to work. I've followed many answers from semi-related questions here and just through tutorials, but I suck. Please help, thanks! :)

REPO: https://github.com/joshzandman/random-joke

Body:
NoMethodError: undefined method jokes' for Class:0x007fbefa5c4160

You are doing it wrong by calling Author.jokes. You should use joins or includes

Author.joins(:jokes)

or

Author.includes(:jokes)

Also, your associations aren't right. You have has_many :jokes in Author which is right but you have has_one :author in Joke which isn't right. Perhaps you should have belongs_to :author. I recommend you to read  associations


问:
Displaying Dicom File as a List of Image Sequence in HTML
I need to display a list of dicom file as image sequence in html and I wonder if it's possible to do so. If it is, how can I achieve the effect? Thanks!</p>

答:
There are a few open source viewers that will help you do this. You can check:

OHIF viewer

GitHub Link: https://github.com/OHIF/Viewers

Demo: http://viewer.ohif.org/

Cornerstone Viewer (used in OHIF viewer)

GitHub: https://github.com/chafey/cornerstone

DICOM Web Viewer

GitHub: https://github.com/ivmartel/dwv


问:
How to disable button based on state?
In my reactjs app I have a button that is disabled/enabled based on a state value:

```<code><button disabled={this.state.modelvalue === 0 ? true : false} onClick={this.showMessage}>Select</button>
</code>```

The modelvalue state is set by changing the select value:

```<code><div className="row">
      <div className="col-md-6">
            <select name="" id="" value={this.state.modelvalue} onChange={this.handleChangeModel}>
              <option value ="0">plse select value</option>
              <option value ="1">One</option>
            </select>
      </div>
</div>

 handleChangeModel(event) {
    this.setState({modelvalue: event.target.value});
 }
</code>```

The handleChangeModel sets the state.modelvalue but for some reason when you change from 'one' back to 'plse select value' the button does not get disabled? Even though the state.modelvalue is 0 again?

答:
Because the selected value will be a string not a number, you need to write the condition like this:

```<code>disabled={this.state.modelvalue === '0'}   //string comparison
</code>```

Update:

As suggested by @RobG, instead of using === (check value with type) use == (check value without type) to check the value, it will work:

```<code>disabled={this.state.modelvalue == 0}
</code>```

Title: How to disable button based on state?

Body:
In my reactjs app I have a button that is disabled/enabled based on a state value:

<button disabled={this.state.modelvalue === 0 ? true : false} onClick={this.showMessage}>Select</button>

The modelvalue state is set by changing the select value:

            <select name="" id="" value={this.state.modelvalue} onChange={this.handleChangeModel}>
              <option value ="0">plse select value</option>
              <option value ="1">One</option>
            </select>

 handleChangeModel(event) {
    this.setState({modelvalue: event.target.value});
 }

The handleChangeModel sets the state.modelvalue but for some reason when you change from 'one' back to 'plse select value' the button does not get disabled? Even though the state.modelvalue is 0 again?

Body:
Because the selected value will be a string not a number, you need to write the condition like this:

disabled={this.state.modelvalue === '0'}   //string comparison

Update:

As suggested by @RobG, instead of using === (check value with type) use == (check value without type) to check the value, it will work:

disabled={this.state.modelvalue == 0}


问:
dynamic variables attached to specific divs
I have several divs with one class on a page.

    ...

I need to attach a variable to each div with a boolean true or false, depending on the click on this div. All these variables should have a default false value, and if I click on a certain div the value of a variable attached to this div should become true. I don't know how much divs there will be as they appear dynamically on a page, so the variables should be attached according to the number of these divs on a page, and they must have a global scope so I could modify them in future. Appreciate all your ideas. Thanks!

答:
You can use the data() method for that purpose:</p>

```<code>$(document).ready(function() {
    $("div").data("yourKey", false).click(function() {
        $(this).data("yourKey", true);
    });
});
</code>```

Body:
You can use the data() method for that purpose:

$(document).ready(function() {
    $("div").data("yourKey", false).click(function() {
        $(this).data("yourKey", true);
    });
});


问:
why JSON.stringify() and JSON.parse does not work?
I have this javascript result:

```<code>var layer = '{"type":"polygon", "coordinates": "-34.32982832836202 149.88922119140625, -34.80027235055681 149.80682373046875, -34.74161249883173 150.30120849609375, -33.99802726234876 150.77362060546875, -33.97980872872456 150.27923583984375"}';
</code>```

I checked it against JSONlint.com and was told it is a valid JSON string.

why can't JSON.parse() and JSON.stringify() not work.

I'm being told by the console that JSON.parse() and JSON.stringify are not recognized functions.

Thanks.

UPDATE 1

ok.  let me try this again.  Sorry, was given bad info.

```<code>var polygon = new Array();
polygon.push('{"type":"polygon", "coordinates": "-34.32982832836202 149.88922119140625, -34.80027235055681 149.80682373046875, -34.74161249883173 150.30120849609375, -33.99802726234876 150.77362060546875, -33.97980872872456 150.27923583984375"}');

var layer = polygon[0]  //should be of value of string just stored
console.log(layer);  //correctly displays JSON string
console.log(JSON.parse(layer));  //line that errors.
</code>```

this is a portion of the full code below:

```<code>// This example requires the Drawing library. Include the libraries=drawing
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=drawing">
var selectedShape;
var drawingManager;
var names = [];
var polygons = new Array();

function initMap() {

    var map = new google.maps.Map(document.getElementById('map'), {
        center: {
            lat: -34.397,
            lng: 150.644
        },
        zoom: 8
    });

    drawingManager = new google.maps.drawing.DrawingManager({
        drawingMode: google.maps.drawing.OverlayType.POLYGON,
        drawingControl: true,
        drawingControlOptions: {
            position: google.maps.ControlPosition.TOP_CENTER,
            drawingModes: ['circle', 'polygon', 'rectangle']
        },
        polygonOptions: {
            editable: true,
            draggable: true
        },
        circleOptions: {
            editable: true,
            draggable: true
        },
        rectangleOptions: {
            editable: true,
            draggable: true
        }

    });
    drawingManager.setMap(map);

    //load preset data

    function setJSON(Shape) {
        console.log(Shape.type);
        if (Shape.type === "circle") {
            return '{"type":"'+Shape.type +'", "lat":"'+Shape.getCenter().lat()+'", "lng":"'+Shape.getCenter().lng()+'", "radius":"'+Shape.getRadius()+'"  }';
        }
        if (Shape.type === "rectangle"){
            return '{"type":"' + Shape.type + ', "start":"'+ Shape.getBounds().getNorthEast() +'", "end":"'+ Shape.getBounds().getSouthWest() +'"}';
        }
        if (Shape.type === "polygon"){
            //eturn '{"type":"'+ Shape.type +'"}' + Shape.getPaths();
            vertice = Shape.getPath();
            console.log("vertice count:  " +  vertice.getLength());
            JSON = '{"type":"'+ Shape.type +'", "coordinates": "';
            vertice.forEach(function(xy, i) {
                JSON = JSON + xy.lat() + ' ' + xy.lng() + ', ';
            });

            JSON = JSON.slice(0,-2) + '"}';
            return JSON;
        }

        return 0
    }

    google.maps.event.addListener(drawingManager, 'overlaycomplete', function(event) {

        drawingManager.setMap(null);

        var newShape = event.overlay;
        newShape.type = event.type;
        selectedShape = newShape;
        console.log(setJSON(selectedShape));

        if (newShape.type === "circle" || newShape.type === "rectangle") {

            google.maps.event.addListener(selectedShape, 'bounds_changed', function(event){
                console.log(setJSON(selectedShape));
            });

        }

        if (newShape.type === "polygon") {

            google.maps.event.addListener(selectedShape.getPath(), 'set_at', function(event) {
                // complete functions
                console.log(setJSON(selectedShape));
            });

            google.maps.event.addListener(selectedShape.getPath(), 'insert_at', function(event) {
                // complete functions
                console.log(setJSON(selectedShape));
            });

            google.maps.event.addListener(selectedShape, 'rightclick', function(event) {
                // Check if click was on a vertex control point
                if (event.vertex === undefined) {
                    return;
                }
                deleteMenu.open(map, selectedShape.getPath(), event.vertex);
                console.log('right-click');
            })

        }

        function DeleteMenu() {
            this.div_ = document.createElement('div');
            this.div_.className = 'delete-menu';
            this.div_.innerHTML = 'Delete';

            var menu = this;
            google.maps.event.addDomListener(this.div_, 'click', function() {
                menu.removeVertex();
            });
        }
        DeleteMenu.prototype = new google.maps.OverlayView();

        DeleteMenu.prototype.onAdd = function() {
            var deleteMenu = this;
            var map = this.getMap();
            this.getPanes().floatPane.appendChild(this.div_);

            // mousedown anywhere on the map except on the menu div will close the
            // menu.
            this.divListener_ = google.maps.event.addDomListener(map.getDiv(), 'mousedown', function(e) {
                if (e.target != deleteMenu.div_) {
                    deleteMenu.close();
                }
            }, true);
        };

        DeleteMenu.prototype.onRemove = function() {
            google.maps.event.removeListener(this.divListener_);
            this.div_.parentNode.removeChild(this.div_);

            // clean up
            this.set('position');
            this.set('path');
            this.set('vertex');
        };

        DeleteMenu.prototype.close = function() {
            this.setMap(null);
        };

        DeleteMenu.prototype.draw = function() {
            var position = this.get('position');
            var projection = this.getProjection();

            if (!position || !projection) {
                return;
            }

            var point = projection.fromLatLngToDivPixel(position);
            this.div_.style.top = point.y + 'px';
            this.div_.style.left = point.x + 'px';
        };

        DeleteMenu.prototype.open = function(map, path, vertex) {
            this.set('position', path.getAt(vertex));
            this.set('path', path);
            this.set('vertex', vertex);
            this.setMap(map);
            this.draw();
        };

        DeleteMenu.prototype.removeVertex = function() {
            var path = this.get('path');
            var vertex = this.get('vertex');

            if (!path || vertex == undefined) {
                this.close();
                return;
            }

            path.removeAt(vertex);
            this.close();
        };

        var deleteMenu = new DeleteMenu();

    });

    google.maps.event.addDomListener(document.getElementById('btnClear'), 'click', function(event) {
        selectedShape.setMap(null);
        drawingManager.setMap(map);
    });

    google.maps.event.addDomListener(document.getElementById('save'), 'click', function(event) {
        names.push($('#polyname').val());
        polygons.push(setJSON(selectedShape));
        length = names.length;
        console.log(length);
        console.log("name:  " + names[length-1] + "; polygon:  " + polygons[length-1]);
    });

    google.maps.event.addDomListener(document.getElementById('btnrecall'), 'click', function(event) {

        $('#btnClear').click();
        console.log($('#btnLoad').val());
        var namefield = $('#btnLoad').val();
        if (namefield !== undefined){
            var polyid = names.indexOf(namefield);
            if (polyid > -1) {
                var layer = polygons[polyid];
                console.log(layer);
                console.log(JSON.parse(JSON.stringify(layer)));

            }else {
                alert("no polygon by that name.  Please Try again");
            }
        }else {
            alert("please enter a name to continue.");
        }

    });

}
</code>```

答:
Apparently, while putting code in at Update #1 above, another question I had placed in stackoverflow had a direct impact on the reason for this question.

why am I getting type errors when hovering over map after layers are set?

as such, I had a variable I called JSON elsewhere in the code.  using JSON as a variable overridden all of the global JSON directives, which denied access to the parse function.

Thanks all guys.

Body:
I have this javascript result:

var layer = '{"type":"polygon", "coordinates": "-34.32982832836202 149.88922119140625, -34.80027235055681 149.80682373046875, -34.74161249883173 150.30120849609375, -33.99802726234876 150.77362060546875, -33.97980872872456 150.27923583984375"}';

I checked it against JSONlint.com and was told it is a valid JSON string.

why can't JSON.parse() and JSON.stringify() not work.

I'm being told by the console that JSON.parse() and JSON.stringify are not recognized functions.

Thanks.

UPDATE 1

ok.  let me try this again.  Sorry, was given bad info.

var polygon = new Array();
polygon.push('{"type":"polygon", "coordinates": "-34.32982832836202 149.88922119140625, -34.80027235055681 149.80682373046875, -34.74161249883173 150.30120849609375, -33.99802726234876 150.77362060546875, -33.97980872872456 150.27923583984375"}');

var layer = polygon[0]  //should be of value of string just stored
console.log(layer);  //correctly displays JSON string
console.log(JSON.parse(layer));  //line that errors.

this is a portion of the full code below:

// This example requires the Drawing library. Include the libraries=drawing
// parameter when you first load the API. For example:
//